跳到主要内容

openid-connect

openid-connect 插件支持与 OpenID Connect (OIDC) 身份提供商(IdP)集成,例如 KeycloakAuth0Microsoft Entra IDGoogleAmazon CognitoOkta 等。它允许 APISIX 在允许或拒绝客户端访问上游受保护资源之前,对其进行身份认证并从身份提供商获取其信息。

示例

授权码流程

授权码流程在 RFC 6749, Section 4.1 中定义。它涉及将临时授权码交换为访问令牌,通常用于机密客户端和公共客户端。

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


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

身份认证成功后,插件将令牌保存在会话 Cookie 中,后续请求将使用存储在 Cookie 中的令牌。

参见 实施授权码授予 了解如何使用 openid-connect 插件通过授权码流程与 Keycloak 集成的示例。

参见使用 PAR 和 DPoP 保护 OIDC,了解如何使用 openid-connect 插件通过 PAR、DPoP、PKCE 和 private_key_jwt 客户端身份认证与 Keycloak 集成。

用于代码交换的证明密钥 (PKCE)

用于代码交换的证明密钥 (PKCE) 在 RFC 7636 中定义。PKCE 通过添加代码挑战和验证器来增强授权码流程,以防止授权码拦截攻击。

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


参见 实施授权码授予 了解如何使用 openid-connect 插件通过带有 PKCE 的授权码流程与 Keycloak 集成的示例。

结合 PAR 和 DPoP 的授权码流程

PAR、PKCE、private_key_jwt 和 DPoP 可以组合在同一个授权码流程中。请分别配置用于客户端身份认证和 DPoP 的签名密钥。此工作流自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起支持。


在此工作流中,网关是向授权服务器发起令牌请求和用户信息请求的 DPoP 客户端。它不会验证外部客户端调用受保护路由时提交的 DPoP 证明。

对于 APISIX 部署,请参阅使用 PAR 和 DPoP 保护 OIDC,其中提供了经过验证的 Keycloak 示例,涵盖密钥生成、配置和验证。

客户端凭据流程

客户端凭据流程在 RFC 6749, Section 4.4 中定义。它涉及客户端使用自己的凭据请求访问令牌以访问受保护资源,通常用于机器对机器的身份认证,不代表特定用户。

下图说明了使用本地 JWT 验证(例如配置 public_keyuse_jwks)实现客户端凭据流程时,不同实体之间的交互:


参见 实施客户端凭据授予 了解如何使用 openid-connect 插件通过客户端凭据流程与 Keycloak 集成的示例。

内省流程

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

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

下图说明了在实现带有令牌内省的授权码流程时不同实体之间的交互:


参见 实施客户端凭据授予 了解如何使用 openid-connect 插件通过带有令牌内省的客户端凭据流程与 Keycloak 集成的示例。

密码流程

密码流程在 RFC 6749, Section 4.3 中定义。它专为受信任的应用程序设计,允许它们直接使用用户的用户名和密码获取访问令牌。在这种授予类型中,客户端应用程序将用户的凭据连同其自己的客户端 ID 和密钥发送到授权服务器,授权服务器随后对用户进行身份认证,如果验证通过,则颁发访问令牌。

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

下图说明了在实现密码流程时不同实体之间的交互:


参见 实施密码授予 了解如何使用 openid-connect 插件通过密码流程与 Keycloak 集成的示例。

刷新令牌授予

刷新令牌授予在 RFC 6749, Section 6 中定义。它使客户端能够在无需用户重新身份认证的情况下,使用以前颁发的刷新令牌请求新的访问令牌。此流程通常在访问令牌过期时使用,允许客户端在无需用户干预的情况下保持对资源的持续访问。刷新令牌在某些 OAuth 流程中与访问令牌一起颁发,其生命周期和安全要求取决于授权服务器的配置。

下图说明了在实现带有刷新令牌流程的密码流程时不同实体之间的交互:


参见 刷新令牌 了解如何使用 openid-connect 插件通过带有令牌刷新的密码流程与 Keycloak 集成的示例。

用户信息

OpenID Connect (OIDC) 中的 UserInfo 端点在 OpenID Connect Core 1.0, Section 5.3 中定义。它使客户端能够通过出示有效的访问令牌来检索有关已认证用户的其他 Claim。此端点对于在用户通过身份认证后获取用户个人资料信息(如姓名、电子邮件和其他属性)特别有用。UserInfo 端点返回的数据取决于访问令牌的范围和授权服务器配置的 Claim。

下图说明了当 APISIX 验证用户信息时不同实体之间的交互:


参见通过检查外部身份提供商的用户信息控制访问,了解如何使用 openid-connect 插件与 Keycloak 集成,并基于用户信息使用 API7 企业版 acl 插件实现访问控制。

故障排除

本节涵盖了在使用此插件时常见的一些问题,以帮助您进行故障排除。

APISIX 无法连接到 OpenID 提供商

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

授权回调中的 State 不匹配

授权状态完成、被重放或被删除后,回调仍可能到达。自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起,Multi Auth 之外过期的 GET 回调会重定向到最初请求的 URL,从而启动新的身份认证流程。如果身份提供商中仍存在 SSO 会话,该流程可以在无需再次提示用户的情况下完成。

使用其他 HTTP 方法、无法恢复目标 URL 或在 Multi Auth 中运行的回调仍会失败,而不会重定向。

身份提供商暂时不可用

在 APISIX 3.18.0 中,如果授权回调包含 OAuth 错误 temporarily_unavailable,且其 state 可以验证,则回调会重定向到最初请求的 URL。这样会重新启动身份认证流程,而不是返回 500 Internal Server Error

其他 OAuth 错误、缺失或无效的 state,以及非 GET 回调不会自动重试。

找不到会话状态

如果您在使用 授权码流程 时遇到 500 internal server error 并在日志中看到以下消息,可能有多种原因。

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

1. 重定向 URI 错误

一种常见配置错误是将 redirect_uri 设置为与路由 URI 相同。当用户请求受保护资源时,请求会在不携带会话 Cookie 的情况下直接到达重定向 URI,从而产生 no session state found 错误。

请把 redirect_uri 配置为完全限定 URI,其路径应当匹配路由,但不能与受保护的请求路径完全相同。例如,如果路由 uri/api/v1/*,请把 redirect_uri 设为 https://gateway.example.com/api/v1/redirect。同时,请在 OpenID 提供商中把同一 URI 配置为允许的重定向 URI。

如果未配置 redirect_uri,或其值是以 / 开头的根相对路径,网关会根据请求的协议方案和主机构建 URI。完全限定 URI 可以避免依赖这个从请求推导的来源。

2. 缺少 Session Secret

bearer_onlyfalse 时,请显式配置 session.secret。无论配置存储在 etcd 中,还是从 Standalone YAML 加载,缺少此字段时 APISIX 都会拒绝插件配置。密钥应至少包含 16 个字符;在多实例部署中,需要读取加密会话 Cookie 的每个网关实例都应使用相同的密钥。

检查 SameSite Cookie 属性是否设置正确(即,如果您的应用程序需要跨站点发送 Cookie),以查看这是否是阻止 Cookie 保存到浏览器 Cookie 存储或从浏览器发送的因素。

4. 上游发送的响应头过大

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

upstream sent too big header while reading response header from upstream

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

或者,调整插件的 session_contents 参数以仅包含必要的信息。例如,要仅包含访问令牌和刷新令牌,您可以按如下方式配置插件:

{
...
"plugins": {
"openid-connect": {
...,
"session_contents": {
"access_token": true
}
}
}
}

可用选项包括 id_tokenuserenc_id_tokenaccess_token(其中包括刷新令牌)。未配置时,所有内容都包含在会话中。

5. 无效的客户端密钥

对于使用共享密钥向身份提供商认证的流程(例如令牌内省,或未使用 PKCE 的授权码流程),请验证 client_secret。在仅使用 Bearer Token 的本地 JWT/JWKS 验证、非 Bearer Token 的 PKCE 流程,以及适用的 private_key_jwt 模式下,此字段为可选。在需要密钥的流程中,无效值会导致认证失败,且不会在会话中存储令牌。

6. PKCE IdP 配置

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

PKCE keycloak configuration