Получение токена обновления от IdentitySever4 - PullRequest
0 голосов
/ 08 ноября 2019

У меня есть веб-приложение Blazor, которое подключается к другому серверу Identity Server 4. Я могу заставить логин работать правильно и передать маркер доступа обратно в Blazor. Однако, когда срок действия токена истекает, я не знаю, как выйти и получить новый токен доступа? Должен ли я получить токен обновления, а затем токен доступа? Я не понимаю, как все это работает.

Код Blazor

services.AddAuthentication(options =>
         {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = AzureADDefaults.AuthenticationScheme;
         })
         .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
         .AddOpenIdConnect(AzureADDefaults.AuthenticationScheme, options =>
         {
            options.Authority = "https://localhost:44382";
            options.RequireHttpsMetadata = true;

            options.ClientId = "client";
            options.ClientSecret = "secret";
            options.ResponseType = "code id_token token";
            options.SaveTokens = true;

            options.Scope.Add("IdentityServerApi");
            options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("email");
            options.Scope.Add("roles");
            options.Scope.Add("offline_access");
         });

IdentityServer4 Setup

...
        new Client
         {
            ClientId = "client",
            ClientSecrets = { new Secret("secret".Sha256()) },
            AllowedGrantTypes = GrantTypes.Hybrid,
            AllowAccessTokensViaBrowser = true,
            RequireClientSecret = true,

            RequireConsent = false,
            RedirectUris = { "https://localhost:44370/signin-oidc" },
            PostLogoutRedirectUris = { "https://localhost:44370/signout-callback-oidc" },
            AllowedScopes = { "openid", "profile", "email", "roles", "offline_access",
               IdentityServerConstants.LocalApi.ScopeName
            },
            AllowedCorsOrigins = { "https://localhost:44370" },

            AlwaysSendClientClaims = true,
            AlwaysIncludeUserClaimsInIdToken = true,

            AllowOfflineAccess = true,
            AccessTokenLifetime = 1,//testing
            UpdateAccessTokenClaimsOnRefresh = true
         },
...

ОБНОВЛЕНИЕ:

Я обновил свой код до offline_access для клиента и сервера (спасибо за обновление ниже). Мой следующий вопрос: как ввести запрос на токен обновления в Blazor, как только я получу отклонение из-за истечения срока действия маркера доступа?

У меня есть приложение Blazor, которое выполняет обратные вызовы API (который проверяет токен доступа)).

   public class APIClient : IAPIClient
   {
      private readonly HttpClient _httpClient;

      //add the bearer token to the APIClient when the client is used
      public APIClient(IHttpContextAccessor httpAccessor, HttpClient client, IConfiguration configuration)
      {
         var accessToken = httpAccessor.HttpContext.GetTokenAsync("access_token").Result;
         client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
         client.DefaultRequestVersion = new Version(2, 0);
         client.BaseAddress = new Uri(configuration["Api_Location"]);
         _httpClient = client;
         _logger = logger;
      }

Что мне нужно добавить в вызовы API для проверки?

Ответы [ 2 ]

0 голосов
/ 13 ноября 2019

Я думаю, что нашел ответ (учитывая толчок Рэнди). Я сделал что-то знакомое для этого поста , где я создал универсальный метод в своем APIClient.

      public async Task<T> SendAsync<T>(HttpRequestMessage requestMessage)
      {
         var response = await _httpClient.SendAsync(requestMessage);
         //test for 403 and actual bearer token in initial request
         if (response.StatusCode == HttpStatusCode.Unauthorized &&
             requestMessage.Headers.Where(c => c.Key == "Authorization")
                     .Select(c => c.Value)
                     .Any(c => c.Any(p => p.StartsWith("Bearer"))))
         {
            var pairs = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("grant_type", "refresh_token"),
                new KeyValuePair<string, string>("refresh_token", _httpAccessor.HttpContext.GetTokenAsync("refresh_token").Result),
                new KeyValuePair<string, string>("client_id", "someclient"),
                new KeyValuePair<string, string>("client_secret", "*****")
            };

            //retry do to token request
            using (var refreshResponse = await _httpClient.SendAsync(
                new HttpRequestMessage(HttpMethod.Post, new Uri(_authLocation + "connect/token"))
                {
                   Content = new FormUrlEncodedContent(pairs)})
               )
            {
               var rawResponse = await refreshResponse.Content.ReadAsStringAsync();
               var x = Newtonsoft.Json.JsonConvert.DeserializeObject<Data.Models.Token>(rawResponse);
               var info = await _httpAccessor.HttpContext.AuthenticateAsync("Cookies");

               info.Properties.UpdateTokenValue("refresh_token", x.Refresh_Token);
               info.Properties.UpdateTokenValue("access_token", x.Access_Token);
               _httpClient.DefaultRequestHeaders.Clear();
               _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", x.Access_Token);

               //retry actual request with new tokens
               response = await _httpClient.SendAsync(new HttpRequestMessage(requestMessage.Method, requestMessage.RequestUri));

            }
         }
         if (typeof(T).Equals(typeof(HttpResponseMessage)))
            return (T)Convert.ChangeType(response, typeof(T));
         else
            return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
      }

Мне не нравится, что я должен вызывать AuthenticateAsync. Тем не менее, похоже, что я нашел способ получить доступ к методу UpdateTokenValue для удаления, а затем повторно добавить новый токен доступа.

0 голосов
/ 09 ноября 2019

Да, вы также должны получить токен обновления, чтобы продолжать получать новые токены доступа. Чтобы получить токен обновления от IdentityServer, вам нужно добавить область «offline_access» в свойстве «AllowedScopes» вашего клиента. Вам также необходимо установить для свойства «AllowOfflineAccess» на своем клиенте значение true.

После этого вам необходимо включить «offline_access» в области, отправленные клиентом, и вы должны получить токен обновления в ответе.

Чтобы использовать токен обновления, отправьте запрос на конечную точку токена со всем, что вы отправили для обмена кодом, за исключением того, что замените параметр «code» на «refresh_token» и измените значение для «grant_type» с «code» на'refresh_token. Ответ IdentityServer4 на этот запрос должен содержать id_token, access_token и новый refresh_token.

...