使用IdentityServer4时用户被锁定如何让旧JTW令牌失效
问题根本原因
JWT属于自包含无状态令牌,默认校验逻辑只会验证签名、有效期、发行方、受众等固有字段,不会主动去身份认证服务校验用户当前状态,因此用户被锁定后,有效期内的已签发JWT默认仍可正常通过API的认证校验。
可行解决方案
方案1:缩短AccessToken有效期搭配Refresh Token(优先推荐,实现成本最低)
- 操作步骤:
- 在IdentityServer4的Client配置中,将
AccessTokenLifetime设置为5~15分钟,同时开启Refresh Token功能,设置合理的RefreshTokenLifetime - 在Refresh Token的签发逻辑中,调用
UserManager.IsLockedOutAsync方法校验用户状态,若用户已被锁定,直接拒绝发放新的AccessToken
- 在IdentityServer4的Client配置中,将
- 优缺点:无需改造现有认证逻辑,性能无额外损耗,最多存在和AccessToken有效期一致的可控窗口期,可满足绝大多数业务场景的安全要求
方案2:实现令牌黑名单机制(需要即时失效且并发量较高时选择)
- 操作步骤:
- 签发JWT时必须携带
jti(JWT唯一标识)声明 - 执行用户锁定操作时,将该用户当前所有有效JWT的
jti存入分布式缓存(如Redis),缓存过期时间设置为对应JWT的过期时间 - 在API的JWT认证中间件中添加自定义校验逻辑,示例代码如下:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Events = new JwtBearerEvents { OnTokenValidated = async context => { // 取当前令牌的唯一标识jti var jti = context.Principal.FindFirst(JwtClaimTypes.Jti)?.Value; var distributedCache = context.HttpContext.RequestServices.GetRequiredService<IDistributedCache>(); // 校验是否在撤销黑名单中 var isRevoked = await distributedCache.GetStringAsync($"revoked_jti:{jti}") != null; if (isRevoked) { context.Fail("当前令牌已被撤销"); } } }; }); - 签发JWT时必须携带
- 优缺点:可实现令牌即时失效,仅增加一次缓存查询开销,性能损耗较低;需要额外维护黑名单缓存,适合对安全性要求高、并发量较大的场景
方案3:使用Reference Token替代JWT(并发量低的内部系统可选)
- 操作步骤:
- 在IdentityServer4的Client配置中,将
AccessTokenType设置为Reference - API端改用内省校验逻辑,每次收到请求时调用IdentityServer的Introspection端点校验令牌有效性
- IdentityServer端在令牌校验逻辑中新增用户锁定状态校验,若用户已锁定直接返回令牌无效
- 在IdentityServer4的Client配置中,将
- 优缺点:令牌状态完全由IdentityServer统一管控,可即时失效;每次API请求都需要额外调用一次IdentityServer的内省接口,性能开销最高,仅适合并发量不高的内部系统场景
内容的提问来源于stack exchange,提问作者Nhat Truong Le
相关产品推荐
相关产品推荐

