跳到主要内容
版本:3.10.x

API7 网关 AI Agent Skill:openid-connect 插件

概览

openid-connect 插件将 API7 企业版与外部 OpenID Connect 身份提供方(Keycloak、Auth0、Okta 等)集成。它支持面向浏览器应用的完整授权码流程、面向 API 客户端的 Bearer Token 校验,以及 Token 内省或本地 JWKS 校验。

适用场景

  • 与企业身份提供方集成,例如 Keycloak、Auth0、Okta、Azure AD
  • 基于浏览器的授权码流程 SSO
  • 使用 Bearer Token 保护 API
  • 跨多个路由集中认证

插件配置参考(路由/服务)

必填字段

字段类型是否必填默认值说明
client_idstringOAuth 2.0 客户端 ID
client_secretstringOAuth 2.0 客户端密钥,在数据库中加密存储
discoverystringOIDC well-known 发现 URL

身份认证与 Scope

字段类型是否必填默认值说明
scopestring"openid"以空格分隔的 OIDC Scope
bearer_onlybooleanfalse仅要求 Bearer Token,不进行重定向
required_scopesarrayBearer Token 中必须包含的 Scope
realmstring"apisix"WWW-Authenticate 请求头中的 Realm

URI 与重定向

字段类型是否必填默认值说明
redirect_uristring{route_uri}/.apisix/redirect身份验证后的重定向 URI
logout_pathstring"/logout"触发退出登录的路径
post_logout_redirect_uristring退出登录后的重定向 URL
unauth_actionstring"auth"未认证时的操作:"auth"(重定向)、"deny"(401)、"pass"(允许)

Token 校验

字段类型是否必填默认值说明
introspection_endpointstringToken 内省端点 URL
public_keystring用于本地 JWT 校验的 PEM 公钥
use_jwksbooleanfalse使用发现文档中的 JWKS 进行本地 JWT 校验
token_signing_alg_values_expectedstring预期的 JWT 签名算法

会话管理

字段类型是否必填默认值说明
session.secretstring是*用于会话加密的至少 16 个字符的密钥,授权码流程必须配置
session.cookie.lifetimeinteger3600会话 Cookie 有效期,单位为秒
session.storagestring"cookie"可选 "cookie""redis"

转发到上游的请求头

字段类型是否必填默认值说明
set_access_token_headerbooleantrue设置 X-Access-Token 请求头
access_token_in_authorization_headerbooleanfalseAuthorization 请求头中设置 Token
set_id_token_headerbooleantrue设置 X-ID-Token 请求头
set_userinfo_headerbooleantrue设置 X-Userinfo 请求头
hide_credentialsbooleanfalse转发到上游前移除身份验证请求头

高级配置

字段类型是否必填默认值说明
ssl_verifybooleanfalse校验 IdP 的 SSL 证书
timeoutinteger3向 IdP 发出请求的超时时间,单位为秒
use_pkcebooleanfalse启用 PKCE(RFC 7636)
renew_access_token_on_expirybooleantrue自动刷新即将过期的 Token

Token 校验模式

1. Token 内省(bearer_only 的默认模式)

API7 企业版会为每个请求调用 IdP 的内省端点。

  • 优点:实时校验,可处理 Token 撤销
  • 缺点:增加延迟(需要网络调用 IdP)
{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://keycloak.example.com/realms/my/.well-known/openid-configuration",
"bearer_only": true,
"introspection_endpoint": "https://keycloak.example.com/realms/my/protocol/openid-connect/token/introspect"
}
}

2. 本地 JWKS 校验

API7 企业版会从发现文档中获取 JWKS,并在本地校验 JWT。

  • 优点:速度快(无需每个请求都调用 IdP),可扩展性好
  • 缺点:在 JWKS 缓存刷新前无法检测已撤销的 Token
{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://keycloak.example.com/realms/my/.well-known/openid-configuration",
"bearer_only": true,
"use_jwks": true
}
}

3. 静态公钥校验

直接提供公钥。无需发现流程或内省调用。

{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://keycloak.example.com/realms/my/.well-known/openid-configuration",
"bearer_only": true,
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjAN...\n-----END PUBLIC KEY-----"
}
}

分步操作:授权码流程(Keycloak)

1. 创建启用 openid-connect 的路由

a7 route create -g default -f - <<'EOF'
{
"id": "oidc-webapp",
"uri": "/app/*",
"plugins": {
"openid-connect": {
"client_id": "apisix-client",
"client_secret": "your-client-secret",
"discovery": "https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration",
"scope": "openid email profile",
"redirect_uri": "http://127.0.0.1:9080/app/redirect",
"session": {
"secret": "my-16-char-secret"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "webapp", "port": 3000, "weight": 1}]
}
}
EOF

2. 流程

  1. 用户访问 http://127.0.0.1:9080/app/dashboard,此时没有会话
  2. API7 企业版将用户重定向到 Keycloak 登录页。
  3. 用户完成认证后,Keycloak 重定向到 http://127.0.0.1:9080/app/redirect?code=...
  4. API7 企业版使用授权码换取 Token,并将其存储到会话 Cookie 中。
  5. 后续请求会自动使用会话 Cookie

分步操作:Bearer Token API 保护

1. 创建用于 API 保护的路由

a7 route create -g default -f - <<'EOF'
{
"id": "oidc-api",
"uri": "/api/*",
"plugins": {
"openid-connect": {
"client_id": "apisix-client",
"client_secret": "your-client-secret",
"discovery": "https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration",
"bearer_only": true,
"use_jwks": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

2. 获取并使用 Token

# 从 IdP 获取 Token
TOKEN=$(curl -s -X POST \
"https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token" \
-d "client_id=apisix-client" \
-d "client_secret=your-client-secret" \
-d "grant_type=client_credentials" \
| jq -r '.access_token')

# 调用 API
curl -i http://127.0.0.1:9080/api/resource \
-H "Authorization: Bearer ${TOKEN}"

提供方发现 URL

提供方发现 URL 模式
Keycloakhttps://{host}/realms/{realm}/.well-known/openid-configuration
Auth0https://{tenant}.auth0.com/.well-known/openid-configuration
Oktahttps://{org}.okta.com/.well-known/openid-configuration
Azure ADhttps://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration
Googlehttps://accounts.google.com/.well-known/openid-configuration

常见模式

Redis 会话存储(分布式部署)

{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://idp.example.com/.well-known/openid-configuration",
"session": {
"secret": "my-16-char-secret",
"storage": "redis",
"redis": {
"host": "redis.example.com",
"port": 6379,
"password": "redis-pass",
"database": 0
}
}
}
}

允许未认证访问(可选认证)

{
"openid-connect": {
"client_id": "my-app",
"client_secret": "secret",
"discovery": "https://idp.example.com/.well-known/openid-configuration",
"bearer_only": true,
"unauth_action": "pass"
}
}

已认证请求会获得身份请求头;未认证请求会继续通过 但不会带有身份信息。

面向公开客户端的 PKCE

{
"openid-connect": {
"client_id": "spa-client",
"client_secret": "secret",
"discovery": "https://idp.example.com/.well-known/openid-configuration",
"use_pkce": true,
"session": {
"secret": "my-16-char-secret"
}
}
}

故障排查

现象原因修复方式
登录后重定向循环redirect_uri 与路由 URI 相同redirect_uri 设置为子路径,例如 /app/redirect
"no session state found"会话 Cookie 未保存检查 session.secret 长度(16 个以上字符)和 SameSite Cookie 策略
有效 Bearer Token 返回 401Token 内省失败验证 introspection_endpoint URL,并检查客户端凭证
连接 IdP 时出现 SSL 错误ssl_verify: true 但证书无效修复证书,或测试时设置 ssl_verify: false
Cookie 过大错误会话数据超过 Cookie 容量切换到 session.storage: "redis"
Token 未刷新renew_access_token_on_expiry: false设置为 true(默认值)

配置同步示例

version: "1"
gateway_groups:
- name: default
routes:
- id: oidc-webapp
uri: /app/*
plugins:
openid-connect:
client_id: apisix-client
client_secret: your-client-secret
discovery: https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration
scope: openid email profile
redirect_uri: http://127.0.0.1:9080/app/redirect
session:
secret: my-16-char-secret
upstream:
type: roundrobin
nodes:
- host: webapp
port: 3000
weight: 1

本页面由 api7/a7 仓库中的 a7-plugin-openid-connect/SKILL.md 生成。你可以在 AI Agent Skills 页面查看所有技能。