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

Glassfish环境下KeycloakOIDCFilter的过期令牌刷新与滑动过期需求

实现Keycloak AccessToken滑动过期的方案(Glassfish环境)

我明白你现在在Glassfish上用org.keycloak.adapters.servlet.KeycloakOIDCFilter做请求拦截和权限校验,想要给AccessToken加上滑动过期的功能对吧?这确实是个很实用的需求,能避免用户频繁被迫重新登录的麻烦。下面我给你梳理下可行的实现思路和具体步骤:

核心原理:利用Refresh Token实现滑动过期

AccessToken本身是JWT格式,过期时间(exp字段)是签发时就固定的,没法直接修改。滑动过期的核心逻辑是:当用户发起有效请求时,若AccessToken快过期了,就用Refresh Token向Keycloak服务器换取新的AccessToken,同时刷新会话的过期时间。

步骤1:先配置Keycloak后台支持刷新令牌

首先得确保你的Keycloak客户端和Realm配置正确,这是滑动过期的基础:

  • 登录Keycloak后台,找到你的目标客户端:
    • 把Access Type设置为confidential(服务端应用推荐)或public(前后端分离场景);
    • 开启Refresh Token Enabled和Direct Access Grants Enabled;
    • 在Advanced Settings里设置Refresh Token Lifespan,建议比你想要的滑动过期时间稍长(比如滑动过期设30分钟,这里就设35分钟)。
  • 进入Realm的Sessions设置页,配置Sso Session Idle Timeout,这个就是你想要的滑动过期时长(比如30分钟)——用户在这个时长内有活跃请求,会话就会自动延长。

步骤2:修改KeycloakOIDCFilter的校验逻辑

你当前的代码只是简单获取并验证AccessToken是否过期,要实现自动滑动过期,需要在每次请求时检查令牌剩余有效期,触发自动刷新:

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    
    // 从请求中获取Keycloak安全上下文
    KeycloakSecurityContext kc = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
    
    if (kc != null) {
        AccessToken accessToken = kc.getToken();
        long currentTimestamp = System.currentTimeMillis() / 1000;
        long timeUntilExpiry = accessToken.getExp() - currentTimestamp;
        
        // 设置刷新阈值:比如剩余5分钟就触发刷新
        long refreshThreshold = 5 * 60;
        
        if (timeUntilExpiry < refreshThreshold) {
            RefreshToken refreshToken = kc.getRefreshToken();
            if (refreshToken == null) {
                // 没有Refresh Token,直接跳转到登录页
                response.sendRedirect(request.getContextPath() + "/login");
                return;
            }
            
            try {
                // 构建Keycloak客户端实例,调用刷新令牌接口
                Keycloak keycloakClient = KeycloakBuilder.builder()
                        .serverUrl("你的Keycloak服务器地址(比如http://localhost:8080/auth)")
                        .realm("你的Realm名称")
                        .clientId("你的客户端ID")
                        .clientSecret("你的客户端秘钥(仅confidential类型需要)")
                        .refreshToken(refreshToken.getToken())
                        .build();
                
                // 执行令牌刷新
                TokenResponse tokenResponse = keycloakClient.tokenManager().refreshToken();
                
                // 解析新的令牌
                AccessToken newAccessToken = RSATokenVerifier.create(tokenResponse.getToken()).getToken();
                RefreshToken newRefreshToken = RefreshToken.fromTokenString(tokenResponse.getRefreshToken());
                
                // 构建新的KeycloakSecurityContext并更新到请求和会话中
                KeycloakSecurityContext newKcContext = new KeycloakSecurityContext(
                        kc.getDeployment(),
                        tokenResponse.getToken(),
                        newAccessToken,
                        tokenResponse.getRefreshToken(),
                        newRefreshToken,
                        kc.getTokenString()
                );
                request.setAttribute(KeycloakSecurityContext.class.getName(), newKcContext);
                request.getSession().setAttribute(KeycloakSecurityContext.class.getName(), newKcContext);
                
            } catch (Exception e) {
                // 刷新失败(比如Refresh Token也过期了),引导用户重新登录
                response.sendRedirect(request.getContextPath() + "/login");
                return;
            }
        }
    }
    
    // 继续执行后续过滤器链
    chain.doFilter(request, response);
}

步骤3:注意事项

  • 避免硬编码配置:把Keycloak服务器地址、Realm、客户端ID/秘钥这些参数放到Glassfish的配置文件(比如web.xml或者自定义配置文件)里,方便后续修改。
  • 异常处理要完善:令牌刷新可能失败(比如网络问题、Refresh Token过期),一定要做好跳转登录的兜底逻辑。
  • 依赖检查:确保Glassfish项目里已经引入了Keycloak Servlet适配器的依赖,比如keycloak-servlet-adapter jar包。
  • 简化方案:如果你的Keycloak版本较新,其实可以不用自己写刷新逻辑——只要Realm和客户端的滑动过期配置正确,Keycloak的内置适配器会自动处理令牌刷新,你只需要确保应用正确保存了会话中的KeycloakSecurityContext即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:47:29