Asp.net-Mvc

在 Asp.Net Identity 中設置 redirect_uri

  • May 29, 2018

我正在嘗試使用 Asp.Net Identity 為 facebook 登錄設置 redirect_uri。但是,僅當 redirect_uri 為“/”時才會觸發GetExternalLoginREST 方法。AccountController如果我添加任何其他它不會觸發GetExternalLogin的內容,瀏覽器只會顯示error: invalid_request

但是,url包含重定向參數,例如,如果我將redirect_uri添加為http://localhost:25432/testing

響應 URL 如下所示:

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

並且瀏覽器視窗顯示:error: invalid_request

知道為什麼這僅在重定向到“/”而不是任何其他網址時有效嗎?

問題是GetExternalLogin註冊為OAuthOptions.AuthorizeEndpointPathwhich used for app.UseOAuthBearerTokens(OAuthOptions)。此配置對端點的參數進行驗證。

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
}

並且您應該傳遞“授權端點請求缺少必需的 response_type 參數”和“授權端點請求包含不支持的 response_type 參數”

對於可能遇到此問題的其他任何人:問題是當您ApplicationOAuthProvider.cs從 Visual Studio SPA 模板中獲取(複製)時,它就在此程式碼所在的位置:

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);
}

這顯然會阻止任何redirect_uri看起來不像的東西http://localhost/http://example.com/例如http://example.com/home不起作用。

現在下面是InvokeAuthorizeEndpointAsyncKatana 的原始碼,它完成了所有工作,您可以看到它呼叫了OAuthProvider可能為此 MVC/Web API 應用程序註冊的任何自定義(此註冊通常發生在 中Startup.Auth.cs):

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;
}

這是關鍵:

await Options.Provider.ValidateClientRedirectUri(clientContext);

因此,您的解決方案是更改ValidateClientRedirectUri執行驗證的方式 - 如您所見,預設的 SPA 實現非常幼稚。

SPA 存在很多問題,主要是因為它缺乏任何有用的資訊,我的意思是對於 ASP.NET 身份和 OWIN 的東西,以及關於 KnockoutJS 實現中發生的事情。

我希望微軟能為這些模板提供更全面的文件,因為任何嘗試做任何更複雜的事情的人都會遇到問題。

我花了幾個小時研究 OWIN (Katana) 原始碼,認為上面的實現阻止了我的重定向 URI,但事實並非如此,希望也能幫助其他人。

高溫高壓

引用自:https://stackoverflow.com/questions/20693082