title: openid-connect keywords:

  • Apache APISIX
  • API 网关
  • OpenID Connect
  • OIDC description: openid-connect 插件支持与 OpenID Connect (OIDC) 身份提供商集成,例如 Keycloak、Auth0、Microsoft Entra ID、Google、Okta 等。它允许 APISIX 对客户端进行身份验证并从身份提供商处获取其信息,然后允许或拒绝其访问上游受保护资源。

描述

openid-connect 插件支持与 OpenID Connect (OIDC) 身份提供商集成,例如 Keycloak、Auth0、Microsoft Entra ID、Google、Okta 等。它允许 APISIX 对客户端进行身份验证,并从身份提供商处获取其信息,然后允许或拒绝其访问上游受保护资源。

属性

名称类型必选项默认值有效值描述
client_idstringOAuth 客户端 ID。
client_secretstringOAuth 客户端 secret。
discoverystringOpenID 提供商的知名发现文档的 URL,其中包含 OP API 端点列表。插件可以直接利用发现文档中的端点。您也可以单独配置这些端点,这优先于发现文档中提供的端点。
scopestringopenid与应返回的有关经过身份验证的用户的信息相对应的 OIDC 范围,也称为 claim。这用于向用户授权适当的权限。默认值为 openid,这是 OIDC 返回唯一标识经过身份验证的用户的 sub 声明所需的范围。可以附加其他范围并用空格分隔,例如 openid email profile
required_scopesarray[string]访问令牌中必须存在的范围。当 bearer_onlytrue 时与自省端点结合使用。如果缺少任何必需的范围,插件将以 403 禁止错误拒绝请求。
realmstringapisix由于持有者令牌无效,WWW-Authenticate 响应标头中的领域伴随 401 未经授权的请求。
bearer_onlybooleanfalse如果为 true,则严格要求在身份验证请求中使用持有者访问令牌。
logout_pathstring/logout激活注销的路径。
post_logout_redirect_uristringlogout_path 收到注销请求后将用户重定向到的 URL。
redirect_uristring通过 OpenID 提供商进行身份验证后重定向到的 URI。请注意,重定向 URI 不应与请求 URI 相同,而应为请求 URI 的子路径。例如,如果路由的 uri/api/v1/*,则 redirect_uri 可以配置为 /api/v1/redirect。如果未配置 redirect_uri,APISIX 将在请求 URI 后附加 /.apisix/redirect 以确定 redirect_uri 的值。
timeoutinteger3[1,...]请求超时时间(秒)。
ssl_verifybooleanfalse如果为 true,则验证 OpenID 提供商的 SSL 证书。
introspection_endpointstring用于自检访问令牌的 OpenID 提供程序的 令牌自检 端点的 URL。如果未设置,则将使用众所周知的发现文档中提供的自检端点作为后备
introspection_endpoint_auth_methodstringclient_secret_basic令牌自检端点的身份验证方法。该值应为 introspection_endpoint_auth_methods_supported 授权服务器元数据 中指定的身份验证方法之一,如众所周知的发现文档中所示,例如 client_secret_basicclient_secret_postprivate_key_jwtclient_secret_jwt
token_endpoint_auth_methodstringclient_secret_basic令牌端点的身份验证方法。该值应为 token_endpoint_auth_methods_supported 授权服务器元数据 中指定的身份验证方法之一,如众所周知的发现文档中所示,例如 client_secret_basicclient_secret_postprivate_key_jwtclient_secret_jwt。如果配置的方法不受支持,则回退到 token_endpoint_auth_methods_supported 数组中的第一个方法。
public_keystring用于验证 JWT 签名 id 的公钥使用非对称算法。提供此值来执行令牌验证将跳过客户端凭据流中的令牌自检。您可以以 -----BEGIN PUBLIC KEY-----\\n……\\n-----END PUBLIC KEY----- 格式传递公钥。
use_jwksbooleanfalse如果为 true 并且未设置 public_key,则使用 JWKS 验证 JWT 签名并跳过客户端凭据流中的令牌自检。JWKS 端点是从发现文档中解析出来的。
use_pkcebooleanfalse如果为 true,则使用 RFC 7636 中定义的授权码流的代码交换证明密钥 (PKCE)。
token_signing_alg_values_expectedstring用于签署 JWT 的算法,例如 RS256
set_access_token_headerbooleantrue如果为 true,则在请求标头中设置访问令牌。默认情况下,使用 X-Access-Token 标头。
access_token_in_authorization_headerbooleanfalse如果为 true 并且 set_access_token_header 也为 true,则在 Authorization 标头中设置访问令牌。
set_id_token_headerbooleantrue如果为 true 并且 ID 令牌可用,则在 X-ID-Token 请求标头中设置值。
set_userinfo_headerbooleantrue如果为 true 并且用户信息数据可用,则在 X-Userinfo 请求标头中设置值。
set_refresh_token_headerbooleanfalse如果为 true 并且刷新令牌可用,则在 X-Refresh-Token 请求标头中设置值。
sessionobjectbearer_onlyfalse 且插件使用 Authorization Code 流程时使用的 Session 配置。
session.secretstring16 个字符以上bearer_onlyfalse 时,用于 session 加密和 HMAC 运算的密钥。
session.cookieobjectCookie 配置。
session.cookie.lifetimeinteger3600Cookie 生存时间(秒)。
unauth_actionstringauth[“auth”,“deny”,“pass”]未经身份验证的请求的操作。设置为 auth 时,重定向到 OpenID 提供程序的身份验证端点。设置为 pass 时,允许请求而无需身份验证。设置为 deny 时,返回 401 未经身份验证的响应,而不是启动授权代码授予流程。
session_contentsobject会话内容配置。如果未配置,将把所有数据存储在会话中。
session_contents.access_tokenboolean若为 true,则将访问令牌存储在会话中。
session_contents.id_tokenboolean若为 true,则将 ID 令牌存储在会话中。
session_contents.enc_id_tokenboolean若为 true,则将加密的 ID 令牌存储在会话中。
session_contents.userboolean若为 true,则将用户信息存储在会话中。
proxy_optsobjectOpenID 提供程序背后的代理服务器的配置。
proxy_opts.http_proxystringHTTP 请求的代理服务器地址,例如 http://<proxy_host>:<proxy_port>
proxy_opts.https_proxystringHTTPS 请求的代理服务器地址,例如 http://<proxy_host>:<proxy_port>
proxy_opts.http_proxy_authorizationstringBasic [base64 用户名:密码]http_proxy 一起使用的默认 Proxy-Authorization 标头值。可以用自定义的 Proxy-Authorization 请求标头覆盖。
proxy_opts.https_proxy_authorizationstringBasic [base64 用户名:密码]https_proxy 一起使用的默认 Proxy-Authorization 标头值。不能用自定义的 Proxy-Authorization 请求标头覆盖,因为使用 HTTPS 时,授权在连接时完成。
proxy_opts.no_proxystring不应代理的主机的逗号分隔列表。
authorization_paramsobject在请求中发送到授权端点的附加参数。
client_rsa_private_keystring用于签署 JWT 以向 OP 进行身份验证的客户端 RSA 私钥。当 token_endpoint_auth_methodprivate_key_jwt 时必需。
client_rsa_private_key_idstring用于计算签名的 JWT 的客户端 RSA 私钥 ID。当 token_endpoint_auth_methodprivate_key_jwt 时可选。
client_jwt_assertion_expires_ininteger60用于向 OP 进行身份验证的签名 JWT 的生命周期,以秒为单位。当 token_endpoint_auth_methodprivate_key_jwtclient_secret_jwt 时使用。
renew_access_token_on_expirybooleantrue如果为 true,则在访问令牌过期或刷新令牌可用时尝试静默更新访问令牌。如果令牌无法更新,则重定向用户进行重新身份验证。
access_token_expires_ininteger如果令牌端点响应中不存在 expires_in 属性,则访问令牌的有效期(以秒为单位)。
refresh_session_intervalinteger刷新用户 ID 令牌而无需重新认证的时间间隔。如果未设置,则不会检查网关向客户端发出的会话的到期时间。如果设置为 900,则表示在 900 秒后刷新用户的 id_token(或浏览器中的会话),而无需重新认证。
iat_slackinteger120ID 令牌中 iat 声明的时钟偏差容忍度(以秒为单位)。
accept_none_algbooleanfalse如果 OpenID 提供程序未签署其 ID 令牌(例如当签名算法设置为none 时),则设置为 true。
accept_unsupported_algbooleantrue如果为 true,则忽略 ID 令牌签名以接受不支持的签名算法。
access_token_expires_leewayinteger0访问令牌续订的过期余地(以秒为单位)。当设置为大于 0 的值时,令牌续订将在令牌过期前设定的时间内进行。这样可以避免访问令牌在到达资源服务器时刚好过期而导致的错误。
force_reauthorizebooleanfalse如果为 true,即使令牌已被缓存,也执行授权流程。
use_noncebooleanfalse如果为 true,在授权请求中启用 nonce 参数。
revoke_tokens_on_logoutbooleanfalse如果为 true,则通知授权服务器,撤销端点不再需要先前获得的刷新或访问令牌。
jwk_expires_ininteger86400JWK 缓存的过期时间(秒)。
jwt_verification_cache_ignorebooleanfalse如果为 true,则强制重新验证承载令牌并忽略任何现有的缓存验证结果。
cache_segmentstring缓存段的可选名称,用于分隔和区分令牌自检或 JWT 验证使用的缓存。
introspection_intervalinteger0缓存和自省访问令牌的 TTL(以秒为单位)。默认值为 0,这意味着不使用此选项,插件默认使用 introspection_expiry_claim 中定义的到期声明传递的 TTL。如果introspection_interval 大于 0 且小于 introspection_expiry_claim 中定义的到期声明传递的 TTL,则使用introspection_interval
introspection_expiry_claimstringexp到期声明的名称,它控制缓存和自省访问令牌的 TTL。
introspection_addon_headersarray[string]用于将其他标头值附加到自省 HTTP 请求。如果原始请求中不存在指定的标头,则不会附加值。
claim_validator.issuer.valid_issuersstring[]将经过审查的 jwt 发行者列入白名单。当用户未传递时,将使用发现端点返回的颁发者。如果两者均缺失,发行人将无法得到验证
claim_schemaobjectOIDC 响应 claim 的 JSON schema。示例:{"type":"object","properties":{"access_token":{"type":"string"}},"required":["access_token"]} - 验证响应中包含必需的字符串字段 access_token

注意:schema 中还定义了 encrypt_fields = {"client_secret"},这意味着该字段将会被加密存储在 etcd 中。具体参考 加密存储字段

此外:你可以使用环境变量或者 APISIX secret 来存放和引用插件配置,APISIX 当前支持通过两种方式配置 secrets - Environment Variables and HashiCorp Vault

例如:你可以使用以下方式来设置环境变量 export keycloak_secret=abc

并且像下面这样在插件里使用

"client_secret": "$ENV://keycloak_secret"

示例

以下示例演示了如何针对不同场景配置 openid-connect 插件。

:::note

您可以这样从 config.yaml 中获取 admin_key 并存入环境变量:

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

:::

Authorization Code Flow

Authorization Code Flow 在 RFC 6749,第 4.1 节 中定义。它涉及用临时授权码交换访问令牌,通常由机密和公共客户端使用。

下图说明了实施 Authorization Code Flow 时不同实体之间的交互:

授权码流程图

当传入请求的标头中或适当的会话 cookie 中不包含访问令牌时,插件将充当依赖方并重定向到授权服务器以继续授权码流程。

成功验证后,插件将令牌保留在会话 cookie 中,后续请求将使用存储在 cookie 中的令牌。

请参阅 实现 Authorization Code Flow以获取使用openid-connect插件通过授权码流与 Keycloak 集成的示例。

Proof Key for Code Exchange (PKCE)

Proof Key for Code Exchange (PKCE) 在 RFC 7636 中定义。PKCE 通过添加代码质询和验证器来增强授权码流程,以防止授权码拦截攻击。

下图说明了使用 PKCE 实现授权码流程时不同实体之间的交互:

使用 PKCE 的授权码流程图

请参阅 实现 Authorization Code Grant,了解使用 openid-connect 插件通过 PKCE 授权码流程与 Keycloak 集成的示例。

Client Credential Flow

Client Credential Flow 在 RFC 6749,第 4.4 节 中定义。它涉及客户端使用自己的凭证请求访问令牌以访问受保护的资源,通常用于机器对机器身份验证,并不代表特定用户。

下图说明了实施 Client Credential Flow 时不同实体之间的交互:

请参阅实现 Client Credentials Grant 获取使用 openid-connect 插件通过客户端凭证流与 Keycloak 集成的示例。

Introspection Flow

Introspection Flow 在 RFC 7662 中定义。它涉及通过查询授权服务器的自省端点来验证访问令牌的有效性和详细信息。

在此流程中,当客户端向资源服务器出示访问令牌时,资源服务器会向授权服务器的自省端点发送请求,如果令牌处于活动状态,则该端点会响应令牌详细信息,包括令牌到期时间、相关范围以及它所属的用户或客户端等信息。

下图说明了使用令牌自省实现 Introspection Flow 时不同实体之间的交互:

请参阅 实现 Client Credentials Grant 以获取使用 openid-connect 插件通过带有令牌自省的客户端凭据流与 Keycloak 集成的示例。

Password Flow

Password Flow 在 RFC 6749,第 4.3 节 中定义。它专为受信任的应用程序而设计,允许它们使用用户的用户名和密码直接获取访问令牌。在此授权类型中,客户端应用程序将用户的凭据连同其自己的客户端 ID 和密钥一起发送到授权服务器,然后授权服务器对用户进行身份验证,如果有效,则颁发访问令牌。

虽然高效,但此流程仅适用于高度受信任的第一方应用程序,因为它要求应用程序直接处理敏感的用户凭据,如果在第三方环境中使用,则会带来重大安全风险。

下图说明了实施 Password Flow 时不同实体之间的交互:

请参阅 实现 Password Grant 获取使用 openid-connect 插件通过密码流与 Keycloak 集成的示例。

Refresh Token Grant

Refresh Token Grant 在 RFC 6749,第 6 节 中定义。它允许客户端使用之前颁发的刷新令牌请求新的访问令牌,而无需用户重新进行身份验证。此流程通常在访问令牌过期时使用,允许客户端无需用户干预即可持续访问资源。刷新令牌与某些 OAuth 流程中的访问令牌一起颁发,其使用寿命和安全要求取决于授权服务器的配置。

下图说明了在实施 Password Grant 和 Refresh Token Grant 时不同实体之间的交互:

请参阅 Refresh Token 获取使用 openid-connect 插件通过带令牌刷新的密码流与 Keycloak 集成的示例。

故障排除

本节介绍使用此插件时的一些常见问题,以帮助您排除故障。

APISIX 无法连接到 OpenID 提供商

如果 APISIX 无法解析或无法连接到 OpenID 提供商,请仔细检查配置文件 config.yaml 中的 DNS 设置并根据需要进行修改。

No Session State Found

如果您在使用授权码流 时遇到 500 内部服务器错误并在日志中显示以下消息,则可能有多种原因。

the error request to the redirect_uri path, but there's no session state found

1. 重定向 URI 配置错误

一个常见的错误配置是将 redirect_uri 配置为与路由的 URI 相同。当用户发起访问受保护资源的请求时,请求直接命中重定向 URI,且请求中没有 session cookie,从而导致 no session state found 错误。

要正确配置重定向 URI,请确保 redirect_uri 与配置插件的路由匹配,但不要完全相同。例如,正确的配置是将路由的 uri 配置为 /api/v1/*,并将 redirect_uri 的路径部分配置为 /api/v1/redirect

您还应该确保 redirect_uri 包含 scheme,例如 httphttps

2. Cookie 未发送或不存在

检查 SameSite cookie 属性是否已正确设置(即您的应用程序是否需要跨站点发送 cookie),看看这是否会成为阻止 cookie 保存到浏览器的 cookie jar 或从浏览器发送的因素。

3. 上游发送的标头太大

如果您有 NGINX 位于 APISIX 前面来代理客户端流量,请查看 NGINX 的 error.log 中是否观察到以下错误:

upstream sent too big header while reading response header from upstream

如果是这样,请尝试将 proxy_buffersproxy_buffer_sizeproxy_busy_buffers_size 调整为更大的值。

另一个选项是配置 session_content 属性来调整在会话中存储哪些数据。例如,你可以将 session_content.access_token 设置为 true

4. 无效的客户端密钥

验证 client_secret 是否有效且正确。无效的 client_secret 将导致身份验证失败,并且不会返回任何令牌并将其存储在 session 中。

5. PKCE IdP 配置

如果您使用授权码流程启用 PKCE,请确保您已将 IdP 客户端配置为使用 PKCE。例如,在 Keycloak 中,您应该在客户端的高级设置中配置 PKCE 质询方法: