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

如何在Keycloak中限制用户访问令牌数量?(Spring Boot场景)

限制Keycloak用户活跃JWT令牌数量的最佳实现方案

1. 切换Spring Security至令牌自省模式

Spring Security默认对JWT采用本地验证(直接校验签名和Claims),不会触发Keycloak的自省端点。要改为调用自省验证,需配置为**不透明令牌(Opaque Token)**模式,Keycloak的自省端点完全兼容OAuth2的令牌自省规范。

配置步骤:

  • 在application.yml中配置自省相关参数:
spring:
  security:
    oauth2:
      resourceserver:
        opaque-token:
          introspection-uri: http://your-keycloak-server/auth/realms/your-realm/protocol/openid-connect/token/introspect
          client-id: your-resource-server-client-id
          client-secret: your-resource-server-client-secret
  • 在SecurityFilterChain中启用opaqueToken验证:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
        .oauth2ResourceServer(oauth2 -> oauth2
            .opaqueToken(opaque -> opaque.introspector(customOpaqueTokenIntrospector())));
    return http.build();
}

2. 实现令牌黑名单存储

要限制活跃令牌数量,需在用户获取新令牌时,将同用户的旧令牌加入黑名单。推荐用Redis作为黑名单存储(支持快速查询和自动过期):

登录/令牌刷新时的黑名单逻辑:

  • 方式一:自定义Keycloak事件监听器(SPI)
    编写Keycloak的EventListenerProvider,监听用户的LOGIN或REFRESH_TOKEN事件,当用户获取新令牌时,从Keycloak的会话中取出该用户的旧令牌,存入Redis黑名单,并设置过期时间与令牌的exp字段一致。
  • 方式二:客户端侧拦截令牌请求
    如果是你的客户端调用Keycloak获取令牌,在拿到新令牌后,调用自定义接口将用户的旧令牌(可从客户端缓存中获取)存入Redis黑名单。

Redis操作示例:

@Autowired
private StringRedisTemplate redisTemplate;

// 将令牌加入黑名单
public void addToBlacklist(String token, long expireTime) {
    redisTemplate.opsForValue().set("token:blacklist:" + token, "invalid", expireTime, TimeUnit.SECONDS);
}

// 检查令牌是否在黑名单中
public boolean isBlacklisted(String token) {
    return Boolean.TRUE.equals(redisTemplate.hasKey("token:blacklist:" + token));
}

3. 在自省流程中加入黑名单校验

自定义OpaqueTokenIntrospector,在Keycloak自省验证通过后,额外检查令牌是否在黑名单中:

@Component
public class CustomOpaqueTokenIntrospector implements OpaqueTokenIntrospector {

    private final OpaqueTokenIntrospector delegate;
    private final TokenBlacklistService blacklistService;

    public CustomOpaqueTokenIntrospector(TokenBlacklistService blacklistService) {
        this.delegate = new NimbusOpaqueTokenIntrospector(
            "http://your-keycloak-server/auth/realms/your-realm/protocol/openid-connect/token/introspect",
            "your-resource-server-client-id",
            "your-resource-server-client-secret"
        );
        this.blacklistService = blacklistService;
    }

    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {
        // 先调用Keycloak自省端点验证令牌有效性
        OAuth2AuthenticatedPrincipal principal = delegate.introspect(token);
        
        // 检查令牌是否在黑名单中
        if (blacklistService.isBlacklisted(token)) {
            throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, "Token is blacklisted", null));
        }
        
        return principal;
    }
}

4. 可选:Keycloak会话限制配合

在Keycloak的Realm配置中,进入Session Settings,设置Maximum Sessions Per User为你想要限制的数量。Keycloak会自动失效用户的旧会话,但JWT本身是无状态的,已颁发的令牌仍会在有效期内有效,因此需要配合上述黑名单+自省的机制,才能彻底限制活跃令牌。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 19:57:18