我正在尝试使用Asp.Net Identity为facebook登录设置redirect_uri。但是,GetExternalLogin
中的AccountController
REST方法仅在redirect_uri为'/'时触发。如果我添加任何其他内容而不会触发GetExternalLogin
,则浏览器仅显示错误:invalid_request 。
然而,url包含重定向参数,因为它应该例如如果我将redirect_uri添加为http://localhost:25432/testing
响应网址如下所示:
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
知道为什么只有在重定向到'/'而不是任何其他url时才能工作?
答案 0 :(得分:23)
对于可能遇到此问题的任何其他人:问题是当您从Visual Studio SPA模板中获取(复制)ApplicationOAuthProvider.cs
时,该代码位于以下位置:
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/
的{{1}},所以例如http://example.com/
无法工作。
现在,以下是Katana中http://example.com/home
的来源,它可以完成所有工作,您可以看到它调用可能为此MVC / Web API应用程序注册的任何自定义InvokeAuthorizeEndpointAsync
(此注册通常发生在OAuthProvider
):
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);
执行验证的方式 - 正如您所见,默认的SPA实施非常幼稚。
有很多人对SPA有问题主要是因为它缺少任何有用的信息,我的意思是ASP.NET身份和OWIN的内容以及KnockoutJS实现中发生的事情。< / p>
我希望微软能够为这些模板提供更全面的文档,因为任何试图做更复杂的事情的人都会遇到问题。
我花了好几个小时,挖掘OWIN(Katana)源代码,认为上面的实现阻止了我的重定向URI,但它不是,希望也可以帮助其他人。
HTH
答案 1 :(得分: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参数”
答案 2 :(得分:3)
根据其他答案,我更改了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);
}