如何通过Docker内部URL正确内省Keycloak访问令牌?
问题
使用Python Keycloak库结合FastAPI验证Keycloak访问令牌时,当server_url设为外部地址https://example.com/auth/时,内省令牌功能正常;但将server_url替换为Docker Compose环境中Keycloak容器的内部地址http://keycloak:8080/auth/后,内省结果始终返回{'active': False}。
相关Python代码:
keycloak_openid = KeycloakOpenID( server_url="https://example.com/auth/", realm_name="abc", client_id="myclient", client_secret_key="secret", verify=False, ) header = request.headers.get('Authorization') token = header.split()[1] token_info = keycloak_openid.introspect(token) print(token_info)
Docker Compose配置:
services: keycloak: image: quay.io/keycloak/keycloak:25.0.2 command: - start - --import-realm - --features=hostname:v2 volumes: - ./config/keycloak/imports:/opt/keycloak/data/import environment: - KC_DB=postgres - KC_DB_URL=jdbc:postgresql://keycloak-db/access-control-db - KC_DB_USERNAME=${POSTGRES_USER} - KC_DB_SCHEMA=public - KC_DB_PASSWORD=${POSTGRES_PASSWORD} - KEYCLOAK_ADMIN=${KEYCLOAK_USER} - KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_PASSWORD} - KC_HOSTNAME=example.com - KC_HOSTNAME_STRICT=false - KC_HTTP_ENABLED=true - KC_HTTP_RELATIVE_PATH=/auth - KC_PROXY_HEADERS=xforwarded depends_on: - keycloak-db restart: always keycloak-db: image: postgres:16 environment: POSTGRES_DB: access-control-db POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - keycloak-db-data:/var/lib/postgresql/data restart: always volumes: keycloak-db-data:
已尝试移除KC_HOSTNAME变量,但问题未解决。
解决方案
出现这个问题的核心原因是:Keycloak颁发的令牌中issuer字段为外部域名https://example.com/auth/realms/abc,当通过内部地址http://keycloak:8080/auth/调用内省接口时,Keycloak默认会校验请求地址与令牌issuer的一致性,不匹配则返回active: False。
可以通过以下两种方法解决:
方法一:修改Keycloak配置,允许内部地址的后台请求
在Docker Compose的Keycloak环境变量中添加以下配置,关闭后台请求的严格校验,并允许内部地址作为合法来源:
environment: # 原有配置保留,新增以下项 - KC_HOSTNAME_STRICT_BACKCHANNEL=false - KC_HOSTNAME_ALLOWED_ORIGINS=http://keycloak:8080,https://example.com - KC_HOSTNAME_STRICT_HTTPS=false
KC_HOSTNAME_STRICT_BACKCHANNEL=false:关闭后台服务(如令牌内省)的主机名严格校验,允许内部地址调用内省接口KC_HOSTNAME_ALLOWED_ORIGINS:添加内部地址和外部域名作为合法来源KC_HOSTNAME_STRICT_HTTPS=false:允许内部HTTP请求(因为内部地址用的是http而非https)
修改后重启Keycloak容器,即可用内部地址正常内省令牌。
方法二:在Python代码中添加Host请求头
无需修改Keycloak配置,在调用内省接口时,手动添加Host请求头为外部域名example.com,让Keycloak认为请求来自合法的issuer地址:
token_info = keycloak_openid.introspect(token, headers={"Host": "example.com"})
这样Keycloak收到请求时,会匹配令牌中的issuer字段,正常返回令牌的活跃状态和其他信息。
内容的提问来源于stack exchange,提问作者Tuff
相关产品推荐
相关产品推荐

