2013-12-19 75 views
13

我想爲Asp.Net身份的Facebook登錄設置redirect_uri。但是,只有在redirect_uri爲'/'時,纔會觸發AccountController中的GetExternalLogin REST方法。如果我添加了其他東西,它不會觸發GetExternalLogin,瀏覽器只顯示* error:invalid_request *。在Asp.Net身份設置redirect_uri

然而,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 

,並在瀏覽器窗口顯示: 錯誤:INVALID_REQUEST

任何想法,爲什麼重定向到「時,這隻能/ '但沒有任何其他網址?

謝謝!

+0

我們需要請參閱'AccountController'中'ExternalLogin'操作的代碼 - 這就是重定向發生的地方 – trailmax

+0

@trailmax實際上,如果您在ASP.NET項目對話框中選擇單頁面應用程序模板並在演示中更改返回URL,則會發生同樣的問題'/'類似於JavaScript文件中的/測試。謝謝! – doorman

回答

4

問題是GetExternalLogin註冊爲OAuthOptions.AuthorizeEndpointPath,它用於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參數」

+0

謝謝:)我在ApplicationOAuthProvider.cs文件中的函數ValidateClientRedirectUri中設置了重定向url,它現在可以工作。 – doorman

+0

有沒有什麼辦法來解決這個問題,並允許** redirect_uri **是一個角度hashbang網址。例如 - **#/ register-external ** – WarrenDodsworth

23

對於其他人可能會遇到這樣的問題:問題是,當你取(複製)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://domain.com/,因此例如http://domain.com/home將不起作用。

現在這下面是卡塔納爲InvokeAuthorizeEndpointAsync的來源,完成所有的工作,你可以看到它調用到可能被註冊此MVC /網絡API的應用程序(此登記通常發生在Startup.Auth.cs)的任何自定義OAuthProvider

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實現,因爲你可以看到,非常天真。

有很多ppl與SPA有關的問題,主要是因爲它缺少任何有用的信息,我的意思是無論是ASP.NET Identity還是OWIN的東西,以及關於KnockoutJS實現中發生的事情。

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

我花了數小時的時間,挖掘到OWIN(Katana)源代碼,認爲它是上述實現阻止我的重定向URI,但它不是,希望可以幫助其他人。

HTH

+1

在發佈此解決方案兩年多後,其瘋狂地發現此帖仍然是該主題信息的最佳來源。 感謝您的幫助! – Cosmosis

+0

微軟故意浪費大量時間開發人員學習他們的中間件CRAP –

2

基於其他的答案,我在ApplicationOAuthProvider.cs改變輸入驗證碼,只是確保重定向URI是在同一個域,像這樣:

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