【问题标题】:Setting the redirect_uri in Asp.Net Identity在 Asp.Net Identity 中设置 redirect_uri
【发布时间】:2013-12-19 22:38:15
【问题描述】:

我正在尝试使用 Asp.Net Identity 为 facebook 登录设置 redirect_uri。但是,AccountController 中的 GetExternalLogin REST 方法仅在 redirect_uri 为 '/' 时才会触发。如果我添加任何其他内容,它不会触发 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
知道为什么这仅在重定向到“/”而不是任何其他网址时有效吗?

【问题讨论】:

  • 我们需要在AccountController 中查看ExternalLogin 操作的代码——这就是重定向发生的地方
  • @trailmax 实际上,如果您在 ASP.NET 项目对话框中选择单页应用程序模板并在演示中将返回 url 从“/”更改为类似 /testing 在 javascript文件。谢谢!

标签: asp.net-mvc facebook asp.net-mvc-5 asp.net-identity


【解决方案1】:

对于可能遇到此问题的其他任何人:问题是当您从 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);
}

这显然会阻止任何看起来不像http://localhost/http://example.com/redirect_uri,因此例如http://example.com/home 将不起作用。

现在下面是 Katana 中 InvokeAuthorizeEndpointAsync 的源代码,它完成了所有工作,您可以看到它调用了可能为此 MVC/Web API 应用程序注册的任何自定义 OAuthProvider(此注册通常发生在 @ 987654329@):

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 实现中发生的事情。

我希望 Microsoft 能够为这些模板提供更全面的文档,因为任何尝试做任何更复杂的事情的人都会遇到问题。

我花了几个小时研究 OWIN (Katana) 源代码,认为是上面的实现阻止了我的重定向 URI,但事实并非如此,希望对其他人也有帮助。

HTH

【讨论】:

  • 在您发布此解决方案 2 年多之后,该帖子仍然是该主题的最佳信息来源,这太疯狂了。感谢您的帮助!
  • 微软故意浪费大量时间让开发人员学习他们的中间件 CRAP
【解决方案2】:

问题是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 参数"

【讨论】:

  • 谢谢 :) 我在 ApplicationOAuthProvider.cs 文件中的 ValidateClientRedirectUri 函数中设置了重定向 url,它现在可以工作了。
  • 有什么办法可以解决这个问题并允许 redirect_uri 成为一个有角度的 hashbang url。例如- #/register-external
【解决方案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);
}

【讨论】:

    猜你喜欢
    • 2016-07-23
    • 2014-05-24
    • 2013-10-18
    • 2014-09-30
    • 2016-06-28
    • 2018-10-19
    • 1970-01-01
    • 2014-04-30
    • 2016-10-03
    相关资源
    最近更新 更多