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

Pac4j v5.7中Keycloak访问令牌续期机制咨询及实现疑问

关于Pac4j v5.7 + Keycloak令牌续期的问题解答

1. Pac4j是否已实现令牌续期机制?

Pac4j的OpenID Connect模块(Keycloak基于此)提供了基于refresh token的续期能力,但默认不会自动触发续期逻辑。要启用该能力,需先完成两项配置:

  • 在Keycloak控制台中,将客户端的Access Type设为confidential,配置客户端密钥,并在Scope中添加offline_access以允许发放refresh token;
  • 在Pac4j的OidcConfiguration中调用withUseRefreshToken(true),并配置正确的客户端密钥。

默认情况下,ProfileManager.removeOrRenewExpiredProfiles()仅会移除已过期的用户profile,不会执行令牌续期操作。

2. 自定义令牌续期的实现方式

若需自动处理令牌续期,推荐以下两种实现路径:

方式一:扩展OidcProfileService

核心逻辑是在获取用户profile时,提前检查access token状态,若已过期或临近过期则触发refresh操作,更新会话中的profile信息:

public class CustomKeycloakProfileService extends OidcProfileService {
    @Override
    public Optional<OidcProfile> retrieveProfile(final WebContext context, final SessionStore sessionStore, final String clientName) {
        Optional<OidcProfile> profile = super.retrieveProfile(context, sessionStore, clientName);
        if (profile.isPresent()) {
            OidcProfile oidcProfile = profile.get();
            Date expirationDate = oidcProfile.getAccessTokenExpirationDate();
            // 提前5分钟检查令牌是否即将过期
            if (expirationDate != null && expirationDate.before(new Date(System.currentTimeMillis() + 5 * 60 * 1000))) {
                // 构造刷新请求并调用Keycloak接口
                TokenRefreshRequest refreshRequest = new TokenRefreshRequest(
                    getConfiguration().getClientId(),
                    getConfiguration().getClientSecret(),
                    oidcProfile.getRefreshToken(),
                    getConfiguration().getTokenEndpoint()
                );
                TokenRefreshResponse refreshResponse = getConfiguration().getHttpClient().postForm(refreshRequest);
                // 更新profile中的令牌信息
                oidcProfile.setAccessToken(refreshResponse.getAccessToken());
                oidcProfile.setRefreshToken(refreshResponse.getRefreshToken());
                oidcProfile.setAccessTokenExpirationDate(refreshResponse.getExpirationDate());
                // 保存更新后的profile到会话
                new ProfileManager(context, sessionStore).save(true, oidcProfile);
            }
        }
        return profile;
    }
}

配置时替换默认的ProfileService:

OidcConfiguration oidcConfig = new OidcConfiguration();
// 配置Keycloak issuer、clientId、clientSecret等参数
oidcConfig.setProfileService(new CustomKeycloakProfileService());

方式二:自定义ProfileManager并重写removeOrRenewExpiredProfiles

如果希望通过removeOrRenewExpiredProfiles统一处理续期逻辑,可重写该方法,在移除过期profile前尝试续期:

public class CustomProfileManager extends ProfileManager {
    public CustomProfileManager(WebContext context, SessionStore sessionStore) {
        super(context, sessionStore);
    }

    @Override
    public void removeOrRenewExpiredProfiles() {
        List<CommonProfile> profiles = getAll(true);
        for (CommonProfile profile : profiles) {
            if (profile instanceof OidcProfile) {
                OidcProfile oidcProfile = (OidcProfile) profile;
                Date expirationDate = oidcProfile.getAccessTokenExpirationDate();
                if (expirationDate != null && expirationDate.before(new Date())) {
                    // 尝试续期,失败则移除profile
                    boolean refreshed = tryRefreshToken(oidcProfile);
                    if (!refreshed) {
                        remove(profile.getId());
                    }
                }
            } else {
                // 非OIDC profile按默认逻辑处理
                if (profile.isExpired()) {
                    remove(profile.getId());
                }
            }
        }
    }

    private boolean tryRefreshToken(OidcProfile oidcProfile) {
        try {
            // 此处复用方式一中的令牌刷新逻辑
            // 更新oidcProfile并保存到会话
            save(true, oidcProfile);
            return true;
        } catch (Exception e) {
            // 续期失败返回false
            return false;
        }
    }
}

后续在业务代码中使用自定义的CustomProfileManager即可。

注意事项

  • 需确保refresh token未过期:可在Keycloak客户端配置中调整Offline Session Idle Timeout和Offline Session Max Lifetime参数;
  • 处理续期失败场景:若refresh token也过期,需引导用户重新登录;
  • 保证线程安全:多线程环境下需避免并发刷新令牌导致的冲突。

内容的提问来源于stack exchange,提问作者João Mendes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 10:03:24