Spring Boot集成Keycloak场景下用户登出后token仍有效问题求解
问题确认
你猜测的情况属实,默认Keycloak Spring适配器采用JWT本地离线校验,仅验证token的签名合法性、有效期、发行方、受众等内置字段,不会每请求都主动调用Keycloak服务端接口校验会话是否被注销。只要token本身未过期,就算Keycloak侧会话已删除,本地校验依然会通过。
根本原因
JWT的设计本身就是无状态的,默认的本地校验逻辑不需要依赖服务端会话状态,能大幅降低认证环节的性能开销,这是默认配置下出现该问题的核心原因。你当前配置的SessionCreationPolicy.STATELESS也关闭了服务端会话存储,进一步导致本地没有会话状态可以校验。
解决方案
你可以根据业务场景选择以下任意一种方案:
- 方案1:缩短Access Token有效期
成本最低的方案,直接在Keycloak对应客户端的设置中,将Access Token有效期调整为3-5分钟。即使用户登出后token还能短时间使用,风险也可控,且完全不影响接口性能,适合大部分业务场景。 - 方案2:启用Token内省校验
适合对安全性要求极高的场景,开启后适配器每次收到请求都会调用Keycloak的内省接口校验token有效性,已注销的token会直接被拦截。需要调整如下配置:- 先在Keycloak管理面板将当前客户端
login-app的访问类型从public改为confidential,保存后在「凭据」页获取客户端秘钥 - 修改application.properties配置:
注意该方案会增加接口响应耗时,高并发场景需要评估性能影响。keycloak.auth-server-url=http://127.0.0.1:8180/auth keycloak.realm=CustomerRealm keycloak.resource=login-app keycloak.ssl-required = none # 关闭public客户端,配置客户端秘钥 keycloak.public-client=false keycloak.credentials.secret=你从Keycloak面板获取的秘钥 # 开启token内省 keycloak.token-introspection-enabled=true - 先在Keycloak管理面板将当前客户端
- 方案3:自建Token黑名单机制
兼顾性能和安全性的方案,实现逻辑如下:- 引入Redis作为公共缓存,用户主动登出时,将当前请求携带的token存入Redis,过期时间设置为和Access Token的有效期一致
- 新增自定义过滤器,放在认证过滤器之前,每次请求先校验当前token是否在黑名单中,存在则直接返回401未认证
该方案不需要每次调用Keycloak接口,性能远高于内省方案,适合高并发业务场景。
内容的提问来源于stack exchange,提问作者Hossein Yazdanfar
相关产品推荐
相关产品推荐

