Identityserver4 从IdentitySever4获取刷新令牌

Identityserver4 从IdentitySever4获取刷新令牌,identityserver4,refresh-token,blazor-server-side,Identityserver4,Refresh Token,Blazor Server Side,我有一个Blazor web应用程序,可以连接到不同的Identity Server 4服务器。我可以让登录正常工作,并将访问令牌传递回Blazor。然而,当令牌到期时,我不知道如何出去获取新的访问令牌?我应该先获得刷新令牌,然后再获得访问令牌吗?我对这一切是如何运作的感到困惑 Blazor代码 services.AddAuthentication(options => { options.DefaultScheme = CookieAuthent

我有一个Blazor web应用程序,可以连接到不同的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设置

...
        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
         },
...
更新:

我已将我的代码更新为客户端和服务器的脱机访问(感谢下面的更新)。我的下一个问题是,一旦我因为访问令牌过期而被拒绝,我如何在Blazor中注入刷新令牌的请求

我让Blazor应用程序调用API(验证访问令牌)


我需要在API调用中添加什么来进行验证?

是的,您还应该获取刷新令牌以继续获取新的访问令牌。要从IdentityServer获取刷新令牌,您需要在客户端的“AllowedScopes”属性中添加“offline_access”范围。您还需要将客户端上的“AllowOfflineAccess”属性设置为true

之后,您需要包括对客户端发送的作用域的“脱机访问”,并且您应该在响应中收到一个刷新令牌


要使用刷新令牌,请向令牌端点发送一个请求,其中包含为代码交换发送的所有内容,但将“code”参数替换为“refresh\u token”,并将“grant\u type”的值从“code”更改为“refresh\u token”。IdentityServer4对此请求的响应应该包含一个id令牌、一个访问令牌和一个新的刷新令牌。

我想我已经找到了答案(考虑到Randy的推送)。我做了一些熟悉的事情,在ApicClient中创建了一个通用方法

      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());
      }
公共异步任务SendAsync(HttpRequestMessage requestMessage) { var response=await\u httpClient.sendsync(requestMessage); //在初始请求中测试403和实际承载令牌 如果(response.StatusCode==HttpStatusCode.Unauthorized&& requestMessage.Headers.Where(c=>c.Key==“授权”) .选择(c=>c.Value) .Any(c=>c.Any(p=>p.StartsWith(“持票人”)) { var pairs=新列表 { 新的KeyValuePair(“授权类型”、“刷新令牌”), 新的KeyValuePair(“刷新令牌”),httpAccessor.HttpContext.GetTokenAsync(“刷新令牌”).Result), 新的KeyValuePair(“客户机id”、“someclient”), 新的KeyValuePair(“客户机密码”,“*****”) }; //重试执行令牌请求 使用(var refreshResponse=await\u httpClient.SendAsync)( 新的HttpRequestMessage(HttpMethod.Post,新Uri(_authLocation+“connect/token”)) { Content=newformurlencodedcontent(对)}) ) { var rawResponse=await refreshResponse.Content.ReadAsStringAsync(); var x=Newtonsoft.Json.JsonConvert.DeserializeObject(rawResponse); var info=wait_httpAccessor.HttpContext.authenticateSync(“Cookies”); info.Properties.UpdateTokenValue(“刷新令牌”,x.refresh\u令牌); info.Properties.UpdateTokenValue(“access\u token”,x.access\u token); _httpClient.DefaultRequestHeaders.Clear(); _httpClient.DefaultRequestHeaders.Authorization=新的AuthenticationHeaderValue(“承载者”,x.Access\U令牌); //使用新令牌重试实际请求 response=waitu httpClient.sendsync(新的HttpRequestMessage(requestMessage.Method,requestMessage.RequestUri)); } } if(typeof(T).等于(typeof(HttpResponseMessage))) return(T)Convert.ChangeType(response,typeof(T)); 其他的 返回Newtonsoft.Json.JsonConvert.DeserializeObject(wait response.Content.ReadAsStringAsync()); } 我不喜欢这样,我得给你打电话。然而,这似乎是我找到的获取UpdateTokenValue方法访问权的方法,以删除并重新添加新的访问令牌

   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;
      }