首页 文章

C#OWIN OAuth2服务器:访问令牌始终返回invalid_grant

提问于
浏览
1

我在这里 Build 一个OAuth2授权服务器:https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server

我有一个授权码,我试图将其换成访问令牌 . 无论如何,我得到400响应“invalid_grant” .

这是我的相关服务器实现:

OAuthAuthorizationServerOptions serverOptions = new OAuthAuthorizationServerOptions()
        {
            AuthorizeEndpointPath = new PathString(authorizePath),
            TokenEndpointPath = new PathString(tokenPath),
            ApplicationCanDisplayErrors = true,
            AllowInsecureHttp = true, // tsk tsk

            Provider = new OAuthAuthorizationServerProvider
            {
                //OnValidateAuthorizeRequest = ValidateAuth,
                OnValidateClientRedirectUri = ValidateClientRedirectUri,
                OnValidateClientAuthentication = ValidateClientAuthentication,
                OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,
                OnGrantClientCredentials = GrantClientCredetails
            },
            // Authorization code provider which creates and receives authorization code
            AuthorizationCodeProvider = new AuthenticationTokenProvider
            {
                OnCreate = CreateAuthenticationCode,
                OnReceive = ReceiveAuthenticationCode
            },

            // Refresh token provider which creates and receives referesh token
            RefreshTokenProvider = new AuthenticationTokenProvider
            {
                OnCreate = CreateRefreshToken,
                OnReceive = ReceiveRefreshToken,
            }
        };

        app.UseOAuthAuthorizationServer(serverOptions);

    private Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
    {
        context.Validated(context.RedirectUri);
        return Task.FromResult(0);
    }

    private Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        string clientId;
        string clientSecret;
        if (context.TryGetBasicCredentials(out clientId, out clientSecret) ||
            context.TryGetFormCredentials(out clientId, out clientSecret))
        {
            context.Validated();
        }
        return Task.FromResult(0);
    }


    private readonly ConcurrentDictionary<string, string> _authenticationCodes =
       new ConcurrentDictionary<string, string>(StringComparer.Ordinal);
    private void CreateAuthenticationCode(AuthenticationTokenCreateContext context)
    {
        context.SetToken(Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"));
        _authenticationCodes[context.Token] = context.SerializeTicket();
    }

    private void ReceiveAuthenticationCode(AuthenticationTokenReceiveContext context)
    {
        string value;

        if (_authenticationCodes.TryRemove(context.Token, out value))
        {
            context.DeserializeTicket(value);
        }
        context.DeserializeTicket(value);
    }

    private void CreateRefreshToken(AuthenticationTokenCreateContext context)
    {
        context.SetToken(context.SerializeTicket());
    }

    private void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
    {
        context.DeserializeTicket(context.Token);
    }

这是我在客户端请求令牌的地方:

var requestPrefix = Request.Scheme + "://" + Request.Host;
        var redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath + "/";

        var body = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("grant_type", "authorization_code"),
                new KeyValuePair<string, string>("code", code),
                new KeyValuePair<string, string>("redirect_uri", redirectUri),
                new KeyValuePair<string, string>("client_id", Options.ClientId),
                new KeyValuePair<string, string>("client_secret", Options.ClientSecret),

            };

        HttpClient _httpClient = new HttpClient();

        var tokenResponse =
            await _httpClient.PostAsync(Constants.GARBAGE_TOKEN, new FormUrlEncodedContent(body));

        var text = await tokenResponse.Content.ReadAsStringAsync();

到目前为止我测试的内容:

  • 我've added breakpoints in all of those provider functions and added context.Validated everywhere I could. Previously, it was not hitting ReceiveAuthenticationCode because the context was not being validated in the ValidateClientAuthentication. This made me assume I was missing a validation step somewhere, but I can't在其他地方找到 .

  • 现在它确实到达ReceiveAuthenticationCode,获取令牌并反序列化票证 . Context.Identity.Ticket不是null并且有数据所以我认为它无论如何都是正确的 .

但在那之后 - 我失去了它的踪迹 . 它回到调用客户端作为“invalid_grant”,我正在试着找出下一个令牌在管道中的位置 . 据推测,正在调用某些提供程序元素,由于某种原因将令牌设置为无效,但我一直在倾倒OAuthAuthorizationServerProvider源代码而我什么都没有,而且似乎没有任何方法可以逐步完成它 . 实际上,即使知道处理发送令牌的实际响应的代码部分也是有用的;这对我来说都是不透明的 .

为什么令牌无效?它实际上是无效还是导致它返回invalid_grant的其他错误?我如何看待这一部分?

我还查看了关于创建一个开始时链接的OAuth2服务器的microsoft doc示例,其中大部分是基于的 . 然而它没有帮助,因为它使用了这个封装所有内容的辅助方法:

var authorizationState = _webServerClient.ProcessUserAuthorization(Request);

所以这并没有告诉我多少,而且我也不确定上面的帮助程序究竟是如何工作的,因为它似乎只能处理auth代码提交和令牌请求 .

1 回答

  • 0

    请求访问令牌时尝试使用 POST 请求 .

相关问题