2013-12-19 38 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); 
     }