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

IdentityServer4登录后如何获取Access Token实现缓存与登出失效

IdentityServer4 基于MemoryCache的Access Token存储、校验与即时失效实现方案

登录环节获取Access Token并存入缓存

  • 不要在业务Controller的登录回调中尝试抓取Access Token,这种方式容易因为Cookie序列化字段丢失、管道流程截断拿不到原始token值,最可靠的获取点是OpenIdConnect认证管道的OnTokenValidated事件,这个事件在应用和IdentityServer完成token交换的瞬间触发,能直接拿到完整的原始响应数据。
  • 首先注册基础依赖:
    builder.Services.AddMemoryCache();
  • 配置OpenIdConnect认证参数时挂载事件,实现token抓取与缓存存储:
    options.Events.OnTokenValidated = async context =>
    {
        // 直接从token端点响应中取Access Token,无额外请求开销
        var accessToken = context.TokenEndpointResponse.AccessToken;
        var userId = context.Principal.FindFirstValue(JwtClaimTypes.Subject);
        // 缓存过期时间和Access Token原生生命周期完全对齐,避免时间差
        var tokenLifetime = int.Parse(context.TokenEndpointResponse.ExpiresIn.ToString());
        
        context.HttpContext.RequestServices.GetService<IMemoryCache>().Set(
            key: $"user_active_token_{userId}",
            value: accessToken,
            absoluteExpirationRelativeToNow: TimeSpan.FromSeconds(tokenLifetime)
        );
    };
    
  • 关键注意点:缓存key固定绑定用户唯一标识,不要直接用Access Token本身做key——后者会导致登出时无法快速定位需要删除的缓存条目。

后续请求的Token合法性校验逻辑

  • 校验逻辑不要写独立的请求中间件重复解析JWT,直接嵌到JwtBearer认证管道的OnTokenValidated事件中,和原生认证流程无缝衔接:
    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            // 保留原有IdentityServer基础配置:Authority、Audience等参数无需修改
            options.Authority = "你的IdentityServer服务地址";
            options.Audience = "受保护的API资源标识";
    
            // 追加自定义缓存校验
            options.Events.OnTokenValidated = async context =>
            {
                // 直接从请求头中提取携带的Access Token
                var requestToken = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
                var userId = context.Principal.FindFirstValue(JwtClaimTypes.Subject);
                
                var cache = context.HttpContext.RequestServices.GetRequiredService<IMemoryCache>();
                var savedValidToken = cache.Get<string>($"user_active_token_{userId}");
    
                // 校验不通过的两种场景:缓存中已无该用户的有效token(已被登出删除)、请求携带的token和缓存中存储的有效token不匹配(使用旧token)
                if (string.IsNullOrEmpty(savedValidToken) || savedValidToken != requestToken)
                {
                    context.Fail("当前Token已失效,请重新登录");
                }
            };
        });
    

登出环节的即时Token失效实现

  • 解决登出后token无法移除的核心逻辑:在登出流程的最起始位置,直接删除对应绑定用户ID的缓存条目,不需要等待IdentityServer的远端登出回调完成:
    [HttpPost]
    public async Task<IActionResult> Logout()
    {
        var cache = HttpContext.RequestServices.GetRequiredService<IMemoryCache>();
        var currentUserId = User.FindFirstValue(JwtClaimTypes.Subject);
        // 直接移除缓存中存储的对应用户有效token
        cache.Remove($"user_active_token_{currentUserId}");
    
        // 后续接入原有登出流程:清除本地认证Cookie、跳转IdentityServer的EndSession端点等
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        return SignOut(
            new AuthenticationProperties { RedirectUri = "/" }, 
            OpenIdConnectDefaults.AuthenticationScheme
        );
    }
    
  • 常见踩坑提醒:
    • 不要把缓存删除逻辑放在远端登出的回调事件中,否则从用户点击登出到回调完成的窗口期内,旧token依然可以正常访问接口,达不到即时失效的效果
    • 如果应用是多实例部署,单实例的MemoryCache存在数据不互通的问题,可以直接将IMemoryCache替换为IDistributedCache的分布式实现(如Redis),现有业务逻辑无需改动
    • 不要依赖IdentityServer默认的JWT无状态校验做全量判断,默认的JWT校验只会验证签名、有效期,无法感知用户主动登出的状态,必须搭配缓存校验才能实现即时失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.31 12:45:06