如何自动刷新Access Token?Blazor应用令牌续期问题
实现Blazor应用中Access Token的自动刷新
1. 先加上offline_access权限范围
要拿到刷新令牌(Refresh Token),必须在认证请求里包含offline_access这个权限,你当前的配置只加了API的权限,补上这行:
options.Scope.Add("offline_access"); // 刷新令牌必备的权限 options.Scope.Add("api://xxxxx/api_access"); // 保留原有的API权限
2. 给Cookie认证加令牌刷新逻辑
通过Cookie认证的OnValidatePrincipal事件,每次验证用户身份时检查Access Token是否过期,过期了就用Refresh Token去换新的令牌,再更新认证票据:
修改AddCookie的配置:
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.Events = new CookieAuthenticationEvents { async OnValidatePrincipal = async context => { // 从当前认证票据里取Access Token和Refresh Token var accessToken = context.Properties.GetTokenValue("access_token"); var refreshToken = context.Properties.GetTokenValue("refresh_token"); if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(refreshToken)) { // 没拿到令牌,直接拒绝身份,让用户重新登录 context.RejectPrincipal(); return; } // 检查Access Token是否还没过期 var tokenHandler = new JwtSecurityTokenHandler(); var jwtToken = tokenHandler.ReadJwtToken(accessToken); if (jwtToken.ValidTo > DateTime.UtcNow) { // 令牌还能用,不用处理 return; } // 调用认证服务器的令牌刷新接口 var config = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>(); var tokenEndpoint = $"{config["Authority"]}/connect/token"; var client = new HttpClient(); var request = new HttpRequestMessage(HttpMethod.Post, tokenEndpoint); request.Content = new FormUrlEncodedContent(new Dictionary<string, string> { ["grant_type"] = "refresh_token", ["client_id"] = "xxxxx", // 替换成你的ClientId ["client_secret"] = "xxxxx", // 替换成你的ClientSecret ["refresh_token"] = refreshToken, ["scope"] = "api://xxxxx/api_access offline_access" // 和之前请求的权限保持一致 }); var response = await client.SendAsync(request); if (!response.IsSuccessStatusCode) { // 刷新失败,拒绝身份,引导用户重新登录 context.RejectPrincipal(); return; } var tokenResponse = await response.Content.ReadFromJsonAsync<Dictionary<string, string>>(); if (tokenResponse == null || !tokenResponse.ContainsKey("access_token")) { context.RejectPrincipal(); return; } // 更新票据里的令牌信息 context.Properties.UpdateTokenValue("access_token", tokenResponse["access_token"]); if (tokenResponse.ContainsKey("refresh_token")) { context.Properties.UpdateTokenValue("refresh_token", tokenResponse["refresh_token"]); } // 更新票据的过期时间(跟着新的Access Token走) var newJwtToken = tokenHandler.ReadJwtToken(tokenResponse["access_token"]); context.Properties.ExpiresUtc = newJwtToken.ValidTo; // 标记需要重新生成认证票据 context.ShouldRenew = true; } }; })
3. 更省心的方式:用HttpClient自动管令牌
在Blazor里,推荐配置专门的HttpClient,让它自动处理令牌的获取和刷新,不用手动调用GetTokenAsync:
注册带令牌处理的HttpClient
builder.Services.AddHttpClient("ApiClient", client => { client.BaseAddress = new Uri("你的API基础地址"); }) .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>(); builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ApiClient")); builder.Services.AddAuthorization();
在组件里直接用这个HttpClient
@inject HttpClient ApiClient // 调用API的时候直接用ApiClient就行,它会自动搞定令牌的事儿 var response = await ApiClient.GetFromJsonAsync<YourResponseType>("api/endpoint");
这种方式会自动依托ASP.NET Core的认证系统处理刷新逻辑,不用自己写一堆代码,更适合Blazor的开发模式。
几个要注意的点
- 得确认你的认证服务器支持
refresh_token授权类型,而且已经给你的客户端开了使用Refresh Token的权限。 - Refresh Token可能有过期时间或者使用次数限制,要是刷新失败了,就得引导用户重新登录。
- 生产环境里尽量用
IHttpClientFactory管理HttpClient实例,别随便新建客户端,避免资源浪费。
内容的提问来源于stack exchange,提问作者Krafter
相关产品推荐
相关产品推荐

