.NET 6 Web App中OAuth2访问令牌过期自动刷新方案咨询
.NET 6 OAuth2访问令牌自动刷新方案
核心思路
利用Cookie认证的OnValidatePrincipal事件,在每次请求验证用户身份时检查访问令牌是否即将过期,若满足条件则调用认证提供商的令牌接口,用refresh token换取新的access token,并更新Cookie中的令牌信息。
步骤1:修改Cookie认证配置,添加刷新逻辑
在原有的AddCookie配置中添加事件处理,实现令牌过期检查与刷新:
.AddCookie(CookieSchemeName, opts => { opts.Events = new CookieAuthenticationEvents { async OnValidatePrincipal(context) { // 从Cookie属性中获取令牌过期时间 if (!context.Properties.Items.TryGetValue(".expires", out var expiresStr) || !DateTimeOffset.TryParse(expiresStr, out var expires)) { // 无法获取过期时间,直接拒绝身份验证 context.RejectPrincipal(); return; } // 提前5分钟触发刷新(可根据业务需求调整阈值) var timeUntilExpiry = expires - DateTimeOffset.UtcNow; if (timeUntilExpiry.TotalMinutes > 5) { // 令牌仍有效,无需处理 return; } // 获取存储的refresh token var refreshToken = await context.HttpContext.GetTokenAsync(AuthSchemeName, "refresh_token"); if (string.IsNullOrEmpty(refreshToken)) { // 无刷新令牌,强制用户重新登录 context.RejectPrincipal(); return; } // 调用认证提供商的令牌刷新接口 var tokenEndpoint = "https://git.example.de/oauth/token"; var httpClient = context.HttpContext.RequestServices.GetRequiredService<HttpClient>(); var formData = new FormUrlEncodedContent(new Dictionary<string, string> { ["grant_type"] = "refresh_token", ["client_id"] = "XXXXXXXXXXXXXXXXXXXXXX", ["client_secret"] = "YYYYYYYYYYYYYYYYYYYYYYYYYY", ["refresh_token"] = refreshToken }); var response = await httpClient.PostAsync(tokenEndpoint, formData); if (!response.IsSuccessStatusCode) { // 刷新失败,强制用户重新登录 context.RejectPrincipal(); return; } // 解析新的令牌数据 var tokenResponse = JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement; var newAccessToken = tokenResponse.GetProperty("access_token").GetString(); var newRefreshToken = tokenResponse.GetProperty("refresh_token").GetString(); var newExpiresIn = tokenResponse.GetProperty("expires_in").GetInt32(); // 更新Cookie中的令牌信息 var updatedProperties = new AuthenticationProperties(context.Properties.Items); updatedProperties.UpdateTokenValue("access_token", newAccessToken); updatedProperties.UpdateTokenValue("refresh_token", newRefreshToken); updatedProperties.ExpiresUtc = DateTimeOffset.UtcNow.AddSeconds(newExpiresIn); // 更新身份信息并标记Cookie需要重新持久化 context.ReplacePrincipal(context.Principal); context.ShouldRenew = true; } }; })
步骤2:控制器获取令牌逻辑保持不变
原有的令牌获取代码无需修改,现在每次获取到的都会是最新的有效令牌:
var accessToken = await HttpContext.GetTokenAsync("MyOauth2", "access_token");
关键注意事项
- 刷新阈值调整:提前刷新的时间(示例中为5分钟)可根据令牌有效期和业务稳定性需求调整,避免令牌刚好过期时API请求失败。
- 错误处理:若refresh token过期或刷新接口调用失败,需强制用户重新登录,避免陷入无效循环。
- 提供商兼容性:确保对接的OAuth2提供商支持refresh_token刷新流程,部分提供商可能限制刷新次数或要求额外权限。
- 代码封装:可将令牌刷新逻辑封装为独立服务(如
IOAuthTokenRefresher),提升代码复用性和可维护性。
内容的提问来源于stack exchange,提问作者perryflynn
相关产品推荐
相关产品推荐

