C # OWIN OAuth2 Server: токен доступа всегда возвращает invalid_grant - PullRequest
0 голосов
/ 31 мая 2018

Я создаю сервер авторизации 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();

То, что я до сих пор тестировал:

  • Я добавил точки останова во всех этих функциях провайдера и добавил контекст. Проверено везде, где только можно.Раньше он не обращался к ReceiveAuthenticationCode, потому что контекст не проверялся в ValidateClientAuthentication.Это заставило меня предположить, что я где-то пропустил этап проверки, но больше нигде не могу найти.
  • Теперь он достигает ReceiveAuthenticationCode, получает токен и десериализует билет.Context.Identity.Ticket не является нулевым и содержит данные, поэтому я все равно предполагаю, что это правильно.

Но после этого - я теряю это.Он обращается к вызывающему клиенту как «invalid_grant», и я вырываю свои волосы, пытаясь выяснить, где в конвейере идет токен.Предположительно, вызывается какой-то элемент провайдера, который по какой-то причине устанавливает токен недействительным, но я пролил на источник OAuthAuthorizationServerProvider, и у меня ничего нет, и, похоже, нет никакого способа пройти через него.Фактически, даже знание части кода, которая обрабатывает фактический ответ отправки токена, было бы полезно;для меня все это непрозрачно.

Почему токен становится недействительным?Это на самом деле признано недействительным или какая-то другая ошибка вызывает возвращение invalid_grant?Как мне взглянуть на эту часть?

Я также просмотрел пример документации Microsoft по созданию сервера OAuth2, связанного с самого начала, на котором основывается большая часть этого.Это, однако, не помогает, потому что он использует этот вспомогательный метод, который инкапсулировал все:

var authorizationState = _webServerClient.ProcessUserAuthorization(Request); 

Так что это не говорит мне много, и я также не уверен в том, как именно работает вышеупомянутый помощник, так как он выглядитдля обработки отправки кода авторизации и запроса токена в одном.

1 Ответ

0 голосов
/ 31 мая 2018

Попробуйте использовать запрос POST при запросе токена доступа.

...