2013-12-19 8 views
13

Ich versuche, die Redirect_uri für die Facebook-Login mit Asp.Net Identität. Die GetExternalLogin-REST-Methode im AccountController wird jedoch nur ausgelöst, wenn redirect_uri '/' ist. Wenn ich etwas anderes hinzufüge, löst es GetExternalLogin nicht aus, der Browser zeigt nur * error: invalid_request *.Einstellung der Redirect_uri in Asp.Net Identität

Die URL enthält jedoch den umgeleiteten Parameter, wie es z. wenn ich die redirect_uri als http://localhost:25432/testing

die Antwort URL sieht wie folgt hinzu:

http://localhost:25432/api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A25432%2Ftesting&state=0NctHHGq_aiazEurHYbvJT8hDgl0GJ_GGSdFfq2z5SA1 

und das Browser-Fenster zeigt: Fehler: invalid_request

Jede Idee, warum dies funktioniert nur, wenn Umleitung zu ‚/ Aber nicht zu anderen URLs?

Danke!

+0

wir brauchen Siehe den Code für 'ExternalLogin' Aktion in' AccountController' - dort findet die Umleitung statt – trailmax

+0

@trailmax Das selbe Problem tritt auf, wenn Sie die Single Page Application Vorlage im ASP.NET Project Dialog auswählen und in der Demo die Return URL ändern '/' zu etwas wie/testing in der Javascript-Datei. Vielen Dank! – doorman

Antwort

4

Das Problem ist, dass GetExternalLogin registriert als OAuthOptions.AuthorizeEndpointPath, die für app.UseOAuthBearerTokens(OAuthOptions) verwendet. Diese Konfiguration setzt die Validierung der Argumente des Endpunkts.

if (!Uri.TryCreate(authorizeRequest.RedirectUri, UriKind.Absolute, out validatingUri)) 
{ 
    // The redirection endpoint URI MUST be an absolute URI 
} 
else if (!String.IsNullOrEmpty(validatingUri.Fragment)) 
{ 
    // The endpoint URI MUST NOT include a fragment component. 
} 
else if (!Options.AllowInsecureHttp && 
        String.Equals(validatingUri.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)) 
{ 
    // The redirection endpoint SHOULD require the use of TLS 
} 

Und Sie sollten „Autorisieren Endpunkt Anforderung fehlt erforderlich response_type Parameter“ übergeben und „Autorisieren Endpunkt Anfrage enthält nicht unterstützte response_type Parameter“

+0

Danke :) Ich habe die Umleitung URL in der Funktion ValidateClientRedirectUri in der Datei ApplicationOAuthProvider.cs und es funktioniert jetzt. – doorman

+0

Gibt es eine Möglichkeit, dies zu umgehen und die ** redirect_uri ** eine eckige Hashbang-URL zu ermöglichen. z.B. - ** #/register-external ** – WarrenDodsworth

23

Für alle anderen, dass in dieser Frage führen könnte: Das Problem ist, wenn Sie nehmen (Kopie) der ApplicationOAuthProvider.cs aus der Visual Studio-Vorlage SPA und es ist dort, wo dieser Code:

public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) 
    { 
     if (context.ClientId == _publicClientId) 
     { 
      var expectedRootUri = new Uri(context.Request.Uri, "/"); 

      if (expectedRootUri.AbsoluteUri == context.RedirectUri) 
      { 
       context.Validated(); 
      } 
     } 

     return Task.FromResult<object>(null); 
    } 

Dies wird sich natürlich blockieren jede redirect_uri, die nicht wie http://localhost/ oder http://domain.com/ aussieht, so zum Beispiel http://domain.com/home wird nicht funktionieren.

Nun darunter ist die Quelle für InvokeAuthorizeEndpointAsync in Katana, die die ganze Arbeit und Sie können es ruft in jeden benutzerdefinierten OAuthProvider sehen, die (in Startup.Auth.cs geschieht in der Regel diese Registrierung) für diese MVC/Web-API-Anwendung registriert werden könnten:

private async Task<bool> InvokeAuthorizeEndpointAsync() 
    { 
     var authorizeRequest = new AuthorizeEndpointRequest(Request.Query); 

     var clientContext = new OAuthValidateClientRedirectUriContext(
      Context, 
      Options, 
      authorizeRequest.ClientId, 
      authorizeRequest.RedirectUri); 

     if (!String.IsNullOrEmpty(authorizeRequest.RedirectUri)) 
     { 
      bool acceptableUri = true; 
      Uri validatingUri; 
      if (!Uri.TryCreate(authorizeRequest.RedirectUri, UriKind.Absolute, out validatingUri)) 
      { 
       // The redirection endpoint URI MUST be an absolute URI 
       // http://tools.ietf.org/html/rfc6749#section-3.1.2 
       acceptableUri = false; 
      } 
      else if (!String.IsNullOrEmpty(validatingUri.Fragment)) 
      { 
       // The endpoint URI MUST NOT include a fragment component. 
       // http://tools.ietf.org/html/rfc6749#section-3.1.2 
       acceptableUri = false; 
      } 
      else if (!Options.AllowInsecureHttp && 
       String.Equals(validatingUri.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)) 
      { 
       // The redirection endpoint SHOULD require the use of TLS 
       // http://tools.ietf.org/html/rfc6749#section-3.1.2.1 
       acceptableUri = false; 
      } 
      if (!acceptableUri) 
      { 
       clientContext.SetError(Constants.Errors.InvalidRequest); 
       return await SendErrorRedirectAsync(clientContext, clientContext); 
      } 
     } 

     await Options.Provider.ValidateClientRedirectUri(clientContext); 

     if (!clientContext.IsValidated) 
     { 
      _logger.WriteVerbose("Unable to validate client information"); 
      return await SendErrorRedirectAsync(clientContext, clientContext); 
     } 

     var validatingContext = new OAuthValidateAuthorizeRequestContext(
      Context, 
      Options, 
      authorizeRequest, 
      clientContext); 

     if (string.IsNullOrEmpty(authorizeRequest.ResponseType)) 
     { 
      _logger.WriteVerbose("Authorize endpoint request missing required response_type parameter"); 
      validatingContext.SetError(Constants.Errors.InvalidRequest); 
     } 
     else if (!authorizeRequest.IsAuthorizationCodeGrantType && 
      !authorizeRequest.IsImplicitGrantType) 
     { 
      _logger.WriteVerbose("Authorize endpoint request contains unsupported response_type parameter"); 
      validatingContext.SetError(Constants.Errors.UnsupportedResponseType); 
     } 
     else 
     { 
      await Options.Provider.ValidateAuthorizeRequest(validatingContext); 
     } 

     if (!validatingContext.IsValidated) 
     { 
      // an invalid request is not processed further 
      return await SendErrorRedirectAsync(clientContext, validatingContext); 
     } 

     _clientContext = clientContext; 
     _authorizeEndpointRequest = authorizeRequest; 

     var authorizeEndpointContext = new OAuthAuthorizeEndpointContext(Context, Options); 

     await Options.Provider.AuthorizeEndpoint(authorizeEndpointContext); 

     return authorizeEndpointContext.IsRequestCompleted; 
    } 

Dies ist der Schlüssel:

 await Options.Provider.ValidateClientRedirectUri(clientContext); 

so Ihre Lösung zu ändern ist, wie die ValidateClientRedirectUri die Validierung durchführt - Implementierung der Standard-SPA ist, wie Sie Kann sehen, sehr naiv.

Es gibt viele Leute, die Probleme mit SPA haben, vor allem, weil es jede Art von nützlichen Informationen fehlt und ich meine sowohl für ASP.NET Identity und OWIN Sachen und in Bezug auf das, was in KnockoutJS Implementierung passiert.

Ich wünschte, Microsoft würde umfassendere Dokumente für diese Vorlagen zur Verfügung stellen, weil jeder, der versuchen wird, etwas etwas Komplexeres zu tun, in Probleme laufen wird.

Ich habe Stunden damit verbracht, in OWIN (Katana) Quellcode zu graben, denkend, dass es die obige Implementierung ist, die meine Redirect URIs blockiert, aber es war nicht, hoffentlich hilft auch jemand anderem.

HTH

+1

Mehr als 2 Jahre, nachdem Sie diese Lösung veröffentlicht haben, ist es verrückt, dass dieser Beitrag immer noch die beste Informationsquelle zu diesem Thema ist. danke für die Hilfe! – Cosmosis

+0

Microsoft hat bewusst viel Zeit damit verschwendet, dass Entwickler ihre Middleware CRAP lernen –

2

Basierend auf den anderen Antworten, änderte ich den Validation Code in ApplicationOAuthProvider.cs, um sicherzustellen, dass nur die Umleitung uri auf der gleichen Domain ist wie so:

public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) 
     { 
      if (context.ClientId == _publicClientId) 
      { 
       Uri expectedRootUri = new Uri(context.Request.Uri, "/"); 

       if (context.RedirectUri.StartsWith(expectedRootUri.AbsoluteUri)) 
       { 
        context.Validated(); 
       } 
      } 

      return Task.FromResult<object>(null); 
     } 
Verwandte Themen