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

Keycloak 19.0.1自定义用户属性JWT缓存过期问题咨询

问题

我使用Keycloak 19.0.1搭配自定义User Storage SPI从遗留数据库加载用户,同时通过该SPI为Keycloak用户模型添加自定义属性,这些属性会包含在调用/token接口签发的JWT令牌中。

目前调用/token接口时,Keycloak能正常签发包含自定义属性的JWT,但当遗留应用更新了数据库中的用户信息后,Keycloak签发的JWT仍携带过时的自定义属性值。我判断这是Keycloak的缓存问题,但没找到正确的配置项来禁用缓存,以确保JWT始终获取最新的自定义属性值。

Keycloak默认支持多种本地和分布式缓存,可通过XML文件配置。我用的是默认的Infinispan缓存模式,已经尝试过以下配置(Docker镜像代码见下方):

  • 构建Keycloak时传递kc.sh build --spi-user-cache-infinispan-enabled=false参数
  • 构建阶段设置环境变量KC_SPI_USER_CACHE_DEFAULT_ENABLED=false
  • 在用户联合中设置NO_CACHE策略,但Keycloak 19版本中该选项存在bug,会导致自定义属性丢失,因此暂不可用

请问应该采用何种缓存配置,才能让Keycloak签发的JWT始终获取最新的自定义属性?是否需要通过XML文件自定义Infinispan配置?具体要修改哪些缓存配置项?

注意:手动失效该用户的所有会话后,Keycloak就能签发包含最新自定义属性的JWT。

FROM <private-/gradle:7.1.0-jdk11 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build --no-daemon

FROM <private-registry>/quay.io_keycloak/keycloak:19.0.1 as builder

ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
ENV KC_DB=postgres
ENV KC_HTTP_RELATIVE_PATH="/auth"

ENV KC_HTTP_ENABLED=true
ENV KC_HOSTNAME_STRICT_HTTPS=false
ENV KC_HOSTNAME_STRICT=false
ENV KC_TRANSACTION_XA_ENABLED=false
ENV KC_SPI_USER_CACHE_DEFAULT_ENABLED=false

COPY --from=build /home/gradle/src/user-storage-spi/build/libs/*.jar /opt/keycloak/providers/
COPY /conf/quarkus.properties /opt/keycloak/conf/quarkus.properties

RUN /opt/keycloak/bin/kc.sh build --spi-user-cache-infinispan-enabled=false

FROM <private-registry>/quay.io_keycloak/keycloak:19.0.1
COPY --from=builder /opt/keycloak/ /opt/keycloak/
WORKDIR /opt/keycloak

ENV KC_HTTP_ENABLED=true
ENV KC_HOSTNAME_STRICT_HTTPS=false
ENV KC_HOSTNAME_STRICT=false
ENV KC_TRANSACTION_XA_ENABLED=false
ENV KC_SPI_USER_CACHE_DEFAULT_ENABLED=false

ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
解决方案

核心问题分析

你之前尝试的用户缓存禁用配置未生效,是因为Keycloak除了用户实体缓存外,还有会话缓存和用户会话缓存会存储已加载的用户属性——即使禁用了用户缓存,已存在的用户会话依然会保留旧属性。另外,User Storage SPI本身的缓存逻辑也可能影响属性刷新。

具体配置方案

1. 自定义Infinispan缓存配置(推荐)

通过XML文件调整users、userSessions、sessions这几个核心缓存的过期策略,确保旧数据快速失效:

  • 在Keycloak的conf目录下创建infinispan.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<infinispan xmlns="urn:infinispan:config:12.1">
    <cache-container name="keycloak">
        <!-- 禁用用户实体缓存,强制每次从数据库加载 -->
        <local-cache name="users">
            <expiration lifespan="0" max-idle="0"/>
        </local-cache>
        <!-- 设置用户会话缓存1分钟过期,确保旧会话快速失效 -->
        <local-cache name="userSessions">
            <expiration lifespan="60000" max-idle="60000"/>
        </local-cache>
        <!-- 同步调整全局会话缓存过期时间 -->
        <local-cache name="sessions">
            <expiration lifespan="60000" max-idle="60000"/>
        </local-cache>
    </cache-container>
</infinispan>
  • 修改Dockerfile的builder阶段,将该文件复制到Keycloak配置目录:
COPY /conf/infinispan.xml /opt/keycloak/conf/

2. 补充SPI层面的缓存控制

在你的自定义User Storage SPI实现中,强制从数据库加载最新用户属性,避免依赖缓存:

@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
    // 直接从遗留数据库加载最新用户数据
    UserModel user = loadUserFromLegacyDB(username);
    if (user != null) {
        // 强制更新Keycloak用户模型中的属性
        updateUserAttributes(user);
    }
    return user;
}

同时,在遗留系统更新用户后,可调用Keycloak Admin API主动失效该用户的所有会话:

curl -X POST "http://<keycloak-host>/auth/admin/realms/<realm>/users/<user-id>/logout" \
  -H "Authorization: Bearer <admin-token>"

3. 修正环境变量配置

确保SPI的缓存策略为DEFAULT(避开有bug的NO_CACHE),结合Infinispan的过期配置实现属性刷新:

KC_SPI_USER_STORAGE_<你的SPI-ID>_CACHE_POLICY=DEFAULT

验证方法

  1. 更新遗留数据库中的用户自定义属性
  2. 调用/token接口获取新JWT
  3. 解码JWT检查自定义属性是否更新
  4. 若未更新,等待1分钟(缓存过期时间)后再次尝试

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 14:19:56