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

如何为IdentityServer、Web API和客户端应用设置Cookie过期时间及刷新Bearer令牌

问题根因

你遇到的现象核心是客户端Cookie有效期、Identity Server会话有效期、Access Token有效期三者不匹配:默认Identity Server4签发的Access Token有效期仅1小时,而你的客户端Cookie没有配置匹配的过期规则,就会出现「客户端看似保持登录、但调用API返回UNAUTHORIZED」的情况。

1. 控制客户端Cookie过期时长

修改客户端AddCookie配置即可自定义Cookie有效期、是否开启滑动过期:

.AddCookie(options =>
{
    options.Cookie.Name = "CorpLense.HR.WebClient";
    // 自定义Cookie过期时长,示例设为8小时
    options.ExpireTimeSpan = TimeSpan.FromHours(8);
    // 关闭滑动过期:到期直接失效;如果开启则用户在过期前半段时间内有访问,会自动刷新Cookie有效期
    options.SlidingExpiration = false;
})

ASP.NET Core认证中间件会自动检测Cookie有效性,Cookie过期后会自动触发登录跳转,无需额外处理。如果需要对齐服务端会话状态,可在配置中增加OnValidatePrincipal事件,每次请求时校验服务端会话是否有效,失效则自动清除Cookie触发登出。

2. Bearer令牌自动刷新

你已经开启了SaveTokens = true,客户端会将access_token、refresh_token、expires_at等值存储在Cookie中,可通过自定义请求拦截器实现Token静默刷新:

2.1 注册Token刷新拦截器

public class TokenRefreshHandler : DelegatingHandler
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IConfiguration _configuration;

    public TokenRefreshHandler(IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
    {
        _httpContextAccessor = httpContextAccessor;
        _configuration = configuration;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var context = _httpContextAccessor.HttpContext;
        var accessToken = await context.GetTokenAsync("access_token");
        var expiresAtStr = await context.GetTokenAsync("expires_at");
        
        // 提前5分钟检查Token是否即将过期
        if (DateTimeOffset.TryParse(expiresAtStr, out var expiresAt) 
            && expiresAt < DateTimeOffset.UtcNow.AddMinutes(5))
        {
            var refreshToken = await context.GetTokenAsync("refresh_token");
            using var tokenClient = new HttpClient();
            var tokenResp = await tokenClient.RequestRefreshTokenAsync(new RefreshTokenRequest
            {
                Address = $"{_configuration["IdentityServerUri"]}/connect/token",
                ClientId = "CorpLense.HR.WebClient",
                ClientSecret = "***",
                RefreshToken = refreshToken
            });

            if (!tokenResp.IsError)
            {
                // 更新Cookie中存储的Token信息
                var authResult = await context.AuthenticateAsync("Cookies");
                authResult.Properties.UpdateTokenValue("access_token", tokenResp.AccessToken);
                authResult.Properties.UpdateTokenValue("refresh_token", tokenResp.RefreshToken);
                authResult.Properties.UpdateTokenValue("expires_at", 
                    DateTimeOffset.UtcNow.AddSeconds(tokenResp.ExpiresIn).ToString("o"));
                await context.SignInAsync("Cookies", authResult.Principal, authResult.Properties);
                accessToken = tokenResp.AccessToken;
            }
            else
            {
                // 刷新失败说明refresh_token也已过期,直接执行登出
                await context.SignOutAsync("Cookies");
                await context.SignOutAsync("oidc");
                context.Response.Redirect("/");
                return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
            }
        }

        request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
        return await base.SendAsync(request, cancellationToken);
    }
}

2.2 关联到API调用客户端

将拦截器注入到你调用Web API的HttpClient管道中,即可实现自动刷新:

services.AddHttpContextAccessor();
services.AddTransient<TokenRefreshHandler>();
services.AddHttpClient("ApiClient", client =>
{
    client.BaseAddress = new Uri(Configuration["ApiBaseUri"]);
}).AddHttpMessageHandler<TokenRefreshHandler>();

3. 服务端全局控制Token与会话有效期

在Identity Server端注册客户端的配置中,可全局控制各类凭证的有效期:

new Client
{
    ClientId = "CorpLense.HR.WebClient",
    // 其他原有配置
    AccessTokenLifetime = 3600, // Access Token有效期,单位秒,默认3600(1小时)
    RefreshTokenLifetime = 86400, // Refresh Token滑动有效期,默认30天
    RefreshTokenUsage = TokenUsage.OneTime, // 每次刷新后更换Refresh Token,安全性更高
    AbsoluteRefreshTokenLifetime = 2592000, // Refresh Token绝对过期时间,默认90天
    UserSsoLifetime = 28800, // SSO会话有效期,和客户端Cookie有效期保持一致即可
}

内容的提问来源于stack exchange,提问作者iffi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 08:06:04