设置 Keycloak 单点登录
OpenID Connect(OIDC)为 OAuth 2.0 添加了身份层,使应用程序能够验证最终用户的身份,并从身份提供商(IdP)获取基本资料信息。在单点登录(SSO)部署中,用户通过 IdP 进行身份认证,并可以访问已连接的应用程序,无需分别登录每个应用程序。
Keycloak 是面向应用程序和服务的开源身份与访问管理平台。它可以直接管理用户或连接外部身份提供商,并通过 OIDC 或 SAML 提供集中式身份认证。在此集成中,Apache APISIX 会先将浏览器身份认证委托给 Keycloak,然后再将请求代理到上游服务。
本指南介绍如何为采用交换授权码证明密钥(PKCE)的 OIDC 授权码流程配置 Keycloak 和 APISIX。当请求没有有效的 APISIX 会话时,APISIX 会将浏览器重定向到 Keycloak。身份认证成功后,APISIX 会使用授权码换取令牌、创建浏览器会话,并继续处理原始请求。
前置条件
配置 Keycloak
启动本地 Keycloak 服务器,然后为浏览器身份认证创建 Realm、OIDC 客户端和用户。
启动 Keycloak
使用临时管理员账号以开发模式启动 Keycloak:
docker run -d --name apisix-keycloak \
-e 'KC_BOOTSTRAP_ADMIN_USERNAME=quickstart-admin' \
-e 'KC_BOOTSTRAP_ADMIN_PASSWORD=quickstart-admin-pass' \
-p 8080:8080 \
quay.io/keycloak/keycloak:26.7.3 start-dev
开发模式和示例凭证仅用于本地测试。生产部署应使用 HTTPS、生产数据库和永久管理员账号。
打开 http://localhost:8080/admin/,使用管理员用户名 quickstart-admin 和密码 quickstart-admin-pass 登录。
创建 Realm
Keycloak Realm 会隔离用户、客户端、角色和其他身份认证资源。为本指南创建一个 Realm:
- 选择 Manage realms → Create realm。
- 输入
quickstart-realm作为 Realm 名称。 - 选择 Create。

创建 OIDC 客户端
将 APISIX 注册为机密 OIDC 客户端:
-
选择 Clients → Create client。
-
保持 Client type 为 OpenID Connect,输入
apisix-quickstart-client作为客户端 ID,然后选择 Next。
-
开启 Client authentication 和 Standard flow。关闭其他身份认证流程,然后选择 Next。
-
在 Valid redirect URIs 下输入
http://localhost:9080/anything/user/callback,然后选择 Save。
-
在 Capability config 中开启 Require PKCE,选择 S256 作为 PKCE 方法,然后选择 Save。
重定向 URI 标识 Keycloak 完成身份认证后将浏览器返回到的 APISIX 端点。在生产环境中,请使用用户可以访问的 HTTPS 端点,并在 Keycloak 中注册完全相同的 URI。
创建用户
创建一个可以通过新 Realm 登录的用户:
-
选择 Users → Create new user。
-
配置以下字段,然后选择 Create:
字段 值 Username quickstart-userEmail quickstart-user@example.comFirst name QuickstartLast name User
-
打开 Credentials 标签页,然后选择 Set password。
-
在 Password 和 Password confirmation 中输入
quickstart-user-pass,关闭 Temporary,然后选择 Save。 -
在确认对话框中选择 Save password。

保存 OIDC 配置
选择 Realm settings。在 General 标签页中找到 Endpoints,然后打开 OpenID Endpoint Configuration。

发现端点的路径如下:
/realms/quickstart-realm/.well-known/openid-configuration
APISIX 容器和浏览器必须能够通过同一主机名访问 Keycloak。将示例地址替换为可访问的主机地址,并把该地址和发现端点保存为环境变量:
export KEYCLOAK_HOST=192.168.1.100
export KEYCLOAK_DISCOVERY="http://${KEYCLOAK_HOST}:8080/realms/quickstart-realm/.well-known/openid-configuration"
选择 Clients → apisix-quickstart-client → Credentials,然后复制客户端密钥。

将客户端 ID 和密钥保存为环境变量:
export KEYCLOAK_CLIENT_ID=apisix-quickstart-client
export KEYCLOAK_CLIENT_SECRET=replace-with-your-client-secret
请妥善保管客户端密钥。生产环境应将凭证存储在 Secret 管理器中,并按照组织的凭证轮换策略进行轮换。
配置 APISIX
配置一个路由,在将请求转发到公共 HTTP 请求与响应服务 httpbin.org 之前,对浏览器请求进行身份认证。/anything/user/* 端点会返回请求详情以供验证。
生成一个唯一密钥,供 APISIX 加密浏览器会话 Cookie 并验证其真实性:
export APISIX_SESSION_SECRET="$(openssl rand -hex 32)"
选择 Admin API 或 ADC 配置路由。
- Admin API
- ADC
通过 Admin API 创建路由:
curl "http://127.0.0.1:9180/apisix/admin/routes/keycloak-sso" -X PUT \
--data-binary @- <<EOF
{
"uri": "/anything/user/*",
"plugins": {
"openid-connect": {
"client_id": "$KEYCLOAK_CLIENT_ID",
"client_secret": "$KEYCLOAK_CLIENT_SECRET",
"discovery": "$KEYCLOAK_DISCOVERY",
"redirect_uri": "http://localhost:9080/anything/user/callback",
"bearer_only": false,
"use_pkce": true,
"scope": "openid profile email",
"session": {
"secret": "$APISIX_SESSION_SECRET"
},
"set_access_token_header": false,
"set_id_token_header": false,
"set_userinfo_header": false
},
"proxy-rewrite": {
"headers": {
"remove": ["Authorization", "Cookie"]
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}
EOF
❶ discovery:Keycloak Realm 的 OIDC 发现文档 URI。
❷ redirect_uri:Keycloak 完成身份认证后将浏览器返回到的 URI。它必须与为 Keycloak 客户端配置的有效重定向 URI 匹配。
❸ bearer_only 和 use_pkce:在没有有效会话时启动浏览器身份认证,并在授权过程中发送 S256 PKCE 质询。
❹ set_access_token_header、set_id_token_header 和 set_userinfo_header:设置为 false,防止 APISIX 将令牌和用户信息添加到上游请求头。
❺ proxy-rewrite.headers.remove:在代理请求之前,移除原始 Authorization 请求头和整个 Cookie 请求头,包括 APISIX 会话 Cookie。如果上游应用程序需要 Cookie,请重新审查此设置。
创建包含路由配置的 adc.yaml 文件:
services:
- name: keycloak-sso
routes:
- name: keycloak-sso
uris:
- /anything/user/*
plugins:
openid-connect:
client_id: "${KEYCLOAK_CLIENT_ID}"
client_secret: "${KEYCLOAK_CLIENT_SECRET}"
discovery: "${KEYCLOAK_DISCOVERY}"
redirect_uri: http://localhost:9080/anything/user/callback
bearer_only: false
use_pkce: true
scope: openid profile email
session:
secret: "${APISIX_SESSION_SECRET}"
set_access_token_header: false
set_id_token_header: false
set_userinfo_header: false
proxy-rewrite:
headers:
remove:
- Authorization
- Cookie
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
❶ discovery:Keycloak Realm 的 OIDC 发现文档 URI。
❷ redirect_uri:Keycloak 完成身份认证后将浏览器返回到的 URI。它必须与为 Keycloak 客户端配置的有效重定向 URI 匹配。
❸ bearer_only 和 use_pkce:在没有有效会话时启动浏览器身份认证,并在授权过程中发送 S256 PKCE 质询。
❹ set_access_token_header、set_id_token_header 和 set_userinfo_header:设置为 false,防止 APISIX 将令牌和用户信息添加到上游请求头。
❺ proxy-rewrite.headers.remove:在代理请求之前,移除原始 Authorization 请求头和整个 Cookie 请求头,包括 APISIX 会话 Cookie。如果上游应用程序需要 Cookie,请重新审查此设置。
ADC 会将服务作为期望状态进行协调。标签选择器将此示例限制在其自身带标签的资源内。请先预览限定范围的变更,并确认其中没有意外更新或删除:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=keycloak-sso
同步已审查的服务配置:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=keycloak-sso
验证身份认证
在浏览器中访问 http://localhost:9080/anything/user/get。APISIX 会将你重定向到 Keycloak。使用用户名 quickstart-user 和密码 quickstart-user-pass 登录。

身份认证成功后,Keycloak 会将浏览器返回到 APISIX,APISIX 随后将请求转发到 httpbin.org。响应应包含类似以下内容的字段:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-CA,en-US;q=0.9,en;q=0.8",
"Host": "localhost",
"Priority": "u=0, i",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "cross-site",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 ...",
"X-Amzn-Trace-Id": "Root=1-...",
"X-Forwarded-Host": "localhost:9080"
},
"json": null,
"method": "GET",
"origin": "192.168.155.1, xxx.xxx.xxx.xxx",
"url": "http://localhost:9080/anything/user/get"
}
请求头值和报 告的来源地址因浏览器和网络环境而异。
上游请求头不应包含 APISIX 会话 Cookie、访问令牌、ID 令牌或用户信息请求头。重新加载页面,验证 APISIX 会复用浏览器会话,而不会将你重定向到 Keycloak。
后续步骤
你已配置 APISIX 使用 Keycloak 对浏览器请求进行身份认证。若要授权来自无最终用户会话的服务请求,请参阅使用 Keycloak 授权 M2M 请求。有关更多配置选项,请参阅 openid-connect 插件参考。