You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 01:07:35