3.2. 使用授权代码流机制
3.2.1. 配置对 OIDC 供应商端点的访问 复制链接链接已复制到粘贴板!
OIDC web-app 应用需要 OIDC 供应商的授权、令牌、JsonWebKey (JWK)集的 URL,以及 UserInfo、introspection 和 end-session (RP-initiated logout)端点。
按照惯例,通过将 /.well-known/openid-configuration 路径添加到配置的 quarkus.oidc.auth-server-url 来发现它们。
或者,如果发现端点不可用,或者您希望减少发现端点往返,您可以禁用端点发现并配置相对路径值。例如:
有些 OIDC 供应商支持元数据发现,但不要返回授权代码流完成或支持应用程序功能所需的所有端点 URL 值,如用户注销。要临时解决这个问题,您可以在本地配置缺少的端点 URL 值,如下例所示:
如果 URL 无法用于本地 Quarkus 端点,并且需要更具体的值,则可以使用同样的配置来覆盖发现的端点 URL。例如,支持全局和特定于应用程序的最终用户会话端点的供应商会返回一个全局最终用户会话 URL,如 http://localhost:8180/oidcprovider/account/global-logout。此 URL 将从当前登录的用户的所有应用中注销用户。但是,如果要求是当前应用程序只将用户从特定应用程序注销,您可以通过设置 quarkus.oidc.end-session=logout 参数来覆盖全局 end-session URL。
3.2.1.1. OIDC 供应商客户端身份验证 复制链接链接已复制到粘贴板!
OIDC 供应商通常需要在与 OIDC 端点交互时识别和验证应用程序。quarkus OIDC,特别是 quarkus.oidc.runtime.OidcProviderClient 类,当必须刷新或内省授权代码时,向 OIDC 供应商进行身份验证。
通常,当授权到 OIDC 供应商时,为给定应用程序定义客户端 ID 和客户端 secret。所有 OIDC 客户端身份验证 选项都被支持。例如:
client_secret_basic 示例:
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/ quarkus.oidc.client-id=quarkus-app quarkus.oidc.credentials.secret=mysecret
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.secret=mysecret
或者:
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/ quarkus.oidc.client-id=quarkus-app quarkus.oidc.credentials.client-secret.value=mysecret
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.client-secret.value=mysecret
以下示例显示了从 凭证供应商 检索的 secret:
client_secret_post示例
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/ quarkus.oidc.client-id=quarkus-app quarkus.oidc.credentials.client-secret.value=mysecret quarkus.oidc.credentials.client-secret.method=post
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.client-secret.value=mysecret
quarkus.oidc.credentials.client-secret.method=post
client_secret_jwt 示例,其签名算法是 HS256:
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/ quarkus.oidc.client-id=quarkus-app quarkus.oidc.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
client_secret_jwt 示例,其中 secret 从 凭证提供程序 检索:
使用 PEM 密钥文件的 private_key_jwt 示例,签名算法为 RS256:。
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/ quarkus.oidc.client-id=quarkus-app quarkus.oidc.credentials.jwt.key-file=privateKey.pem
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.jwt.key-file=privateKey.pem
使用密钥存储文件的 private_key_jwt 示例,签名算法为 RS256:
使用 client_secret_jwt 或 private_key_jwt 身份验证方法可确保客户端 secret 没有发送到 OIDC 供应商,因此避免了被 'man-in-the-middle' 攻击所截获的 secret 的风险。
3.2.1.1.1. 其他 JWT 身份验证选项 复制链接链接已复制到粘贴板!
如果使用 client_secret_jwt、private_key_jwt 或 Apple post_jwt 身份验证方法,您可以自定义 JWT 签名算法、密钥标识符、使用者、主题和签发者。例如:
3.2.1.1.2. Apple POST JWT 复制链接链接已复制到粘贴板!
Apple OIDC 供应商使用 client_secret_post 方法,其中 secret 是使用 private_key_jwt 身份验证方法生成的 JWT,但使用 Apple 帐户特定的签发者和主题声明。
在 Quarkus Security 中,quarkus-oidc 支持非标准 client_secret_post_jwt 身份验证方法,如下所示:
3.2.1.1.3. Mutual TLS (mTLS) 复制链接链接已复制到粘贴板!
有些 OIDC 供应商可能需要客户端作为 mutual TLS 身份验证过程的一部分进行身份验证。
以下示例演示了如何配置 quarkus-oidc 以支持 mTLS :
3.2.1.1.4. POST 查询 复制链接链接已复制到粘贴板!
有些供应商(如 Strava OAuth2 供应商 )需要发布客户端凭证作为 HTTP POST 查询参数:
quarkus.oidc.provider=strava quarkus.oidc.client-id=quarkus-app quarkus.oidc.credentials.client-secret.value=mysecret quarkus.oidc.credentials.client-secret.method=query
quarkus.oidc.provider=strava
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.client-secret.value=mysecret
quarkus.oidc.credentials.client-secret.method=query
3.2.1.2. 内省端点身份验证 复制链接链接已复制到粘贴板!
有些 OIDC 供应商需要使用基本身份验证以及与 client_id 和 client_secret 不同的凭证进行身份验证。如果您之前已将安全身份验证配置为支持 client_secret_basic 或 client_secret_post 客户端身份验证方法,如 OIDC 供应商 客户端身份验证部分中所述,您可能需要应用额外的配置,如下所示。
如果必须内省令牌,并且需要内省特定于内省端点的身份验证机制,您可以配置 quarkus-oidc,如下所示:
quarkus.oidc.introspection-credentials.name=introspection-user-name quarkus.oidc.introspection-credentials.secret=introspection-user-secret
quarkus.oidc.introspection-credentials.name=introspection-user-name
quarkus.oidc.introspection-credentials.secret=introspection-user-secret
3.2.1.3. OIDC 请求过滤器 复制链接链接已复制到粘贴板!
您可以通过注册一个或多个 OidcRequestFilter 实现(可以更新或添加新的请求标头)来过滤 Quarkus 向 OIDC 供应商发出的 OIDC 请求,也可以记录请求。
例如:
或者,您可以使用 OidcRequestFilter.Endpoint enum 将此过滤器仅应用到令牌端点请求:
- 1
- 将这个过滤器限制为只针对 OIDC 发现端点的请求。
3.2.1.4. 重定向至 OIDC 供应商 复制链接链接已复制到粘贴板!
当用户重定向到 OIDC 供应商以进行身份验证时,重定向 URL 包含一个 redirect_uri 查询参数,该参数表示在身份验证完成后必须重定向到的供应商。在我们的情形中,这是 Quarkus 应用程序。
默认情况下,quarkus 将此参数设置为当前应用程序请求 URL。例如,如果用户试图访问 http://localhost:8080/service/1 上的 Quarkus 服务端点,则 redirect_uri 参数被设置为 http://localhost:8080/service/1。同样,如果请求 URL 是 http://localhost:8080/service/2,则 redirect_uri 参数被设置为 http://localhost:8080/service/2。
有些 OIDC 供应商要求将 redirect_uri 的值与给定应用程序的值相同,例如 http://localhost:8080/service/callback,用于所有重定向 URL。在这种情况下,必须设置 quarkus.oidc.authentication.redirect-path 属性。例如,quarkus.oidc.authentication.redirect-path=/service/callback,Quarkus 会将 redirect_uri 参数设置为绝对 URL,如 http://localhost:8080/service/callback,它都相同,无论当前请求 URL 都相同。
如果设置了 quarkus.oidc.authentication.redirect-path,但您需要在用户重定向到唯一回调 URL 后恢复原始请求 URL,例如 http://localhost:8080/service/callback,将 quarkus.oidc.authentication.restore-path-after-redirect 属性设置为 true。这将恢复请求 URL,如 http://localhost:8080/service/1。
3.2.1.5. 自定义身份验证请求 复制链接链接已复制到粘贴板!
默认情况下,只有 response_type (设置为 代码)、scope (设置为 openid)、client_id、redirect_uri、以及 status 属性在用户重定向到时传递给 OIDC 供应商的授权端点。
您可以使用 quarkus.oidc.authentication.extra-params 添加更多属性。例如,有些 OIDC 供应商可能会选择返回授权代码作为重定向 URI 片段的一部分,这会中断身份验证过程。以下示例演示了如何解决这个问题:
quarkus.oidc.authentication.extra-params.response_mode=query
quarkus.oidc.authentication.extra-params.response_mode=query
3.2.1.6. 自定义身份验证错误响应 复制链接链接已复制到粘贴板!
当用户重定向到 OIDC 授权端点以进行身份验证时,如果需要,授权 Quarkus 应用程序,这个重定向请求可能会失败,例如,当重定向 URI 中包含无效的范围时。在这种情况下,供应商会将用户重新重定向到 Quarkus,并带有 error 和 error_description 参数,而不是预期的 代码 参数。
例如,当重定向到提供程序的无效范围或其他无效参数时,可能会发生这种情况。
在这种情况下,默认会返回 HTTP 401 错误。但是,您可以请求调用自定义公共错误端点,以返回更用户友好的 HTML 错误页面。要做到这一点,请设置 quarkus.oidc.authentication.error-path 属性,如下例所示:
quarkus.oidc.authentication.error-path=/error
quarkus.oidc.authentication.error-path=/error
确保属性以正斜杠(/)字符开头,并且路径相对于当前端点的基本 URI。例如,如果设为 '/error',并且当前请求 URI 为 https://localhost:8080/callback?error=invalid_scope,则向 https://localhost:8080/error?error=invalid_scope 发出最终重定向。
若要防止用户重定向到此页面,需要重新验证,请确保此错误端点为公共资源。
3.2.2. 访问授权数据 复制链接链接已复制到粘贴板!
您可以通过不同的方式访问授权信息。
3.2.2.1. 访问 ID 和访问令牌 复制链接链接已复制到粘贴板!
OIDC 代码身份验证机制在授权代码流期间获取三个令牌: ID 令牌、访问令牌和刷新令牌。
ID 令牌始终是一个 JWT 令牌,代表使用 JWT 声明进行用户身份验证。您可以使用它来发出 OIDC 端点、用户名以及名为 声明 的其他信息。您可以使用 IdToken qualifier 注入 JsonWebToken 来访问 ID 令牌声明:
OIDC web-app 应用程序通常使用访问令牌代表当前登录的用户访问其他端点。您可以访问原始访问令牌,如下所示:
如果发布到 Quarkus web-app 应用的访问令牌是不透明的,并且无法解析到 JsonWebToken,或者应用程序需要内内容,则使用 AccessTokenCredential。
@RequestScoped 和 @ApplicationScoped 上下文都支持 JsonWebToken 和 AccessTokenCredential 注入。
quarkus OIDC 使用刷新令牌来刷新当前的 ID 和访问令牌,作为其 会话管理 过程的一部分。
3.2.2.2. 用户信息 复制链接链接已复制到粘贴板!
如果 ID 令牌没有提供有关当前经过身份验证的用户的足够信息,您可以从 UserInfo 端点获取更多信息。设置 quarkus.oidc.authentication.user-info-required=true 属性,从 OIDC UserInfo 端点请求 UserInfo JSON 对象。
使用通过授权代码授权响应返回的访问令牌将向 OIDC 提供程序 UserInfo 端点发送请求,以及一个 io.quarkus.oidc.UserInfo (一个简单的 jakarta.json.JsonObject wrapper)对象被创建。io.quarkus.oidc.UserInfo 可以作为 SecurityIdentity userinfo 属性注入或访问。
3.2.2.3. 访问 OIDC 配置信息 复制链接链接已复制到粘贴板!
当前租户的发现的 OpenID Connect 配置元数据 由 io.quarkus.oidc.OidcConfigurationMetadata 表示,并可作为 SecurityIdentity configuration-metadata 属性注入或访问。
如果端点是 public,则默认租户的 OidcConfigurationMetadata 会被注入。
3.2.2.4. 映射令牌声明和 SecurityIdentity 角色 复制链接链接已复制到粘贴板!
角色从验证令牌映射到 SecurityIdentity 角色的方式与为 Bearer 令牌 的方式相同。唯一的区别是 ID 令牌 默认用作角色的来源。
如果使用 Keycloak,请为 ID 令牌设置 microprofile-jwt 客户端范围,使其包含 组 声明。如需更多信息,请参阅 Keycloak 服务器管理指南。
但是,根据您的 OIDC 供应商,角色可能会存储在访问令牌或用户信息中。
如果访问令牌包含角色,并且此访问令牌不应传播到下游端点,则设置 quarkus.oidc.roles.source=accesstoken。
如果 UserInfo 是角色的来源,则设置 quarkus.oidc.roles.source=userinfo,如果需要,quarkus.oidc.roles.role-claim-path。
另外,您还可以使用自定义 SecurityIdentityAugmentor 来添加角色。如需更多信息,请参阅安全身份管理 自定义。您还可以使用 HTTP 安全策略 将创建从令牌声明创建的 SecurityIdentity 角色映射到特定于部署的角色。
3.2.3. 确保令牌和身份验证数据的有效性 复制链接链接已复制到粘贴板!
身份验证过程的一个核心部分是确保信息的信任链和有效性。这可以通过确保令牌可以被信任来实现。
3.2.3.1. 令牌验证和内省 复制链接链接已复制到粘贴板!
OIDC 授权代码流令牌的验证过程遵循 Bearer 令牌身份验证令牌验证和内省逻辑。如需更多信息,请参阅"Quarkus OpenID Connect (OIDC) Bearer 令牌身份验证"指南中的令牌验证和内省部分。https://docs.redhat.com/en/documentation/red_hat_build_of_quarkus/3.8/html/openid_connect_oidc_authentication/security-oidc-bearer-token-authentication#bearer-token-token-verification-introspection
使用 Quarkus web-app 应用程序时,默认只验证 IdToken,因为访问令牌没有用于访问当前的 Quarkus web-app 端点,并旨在传播到预期此访问令牌的服务。如果您希望访问令牌包含访问当前 Quarkus 端点所需的角色(quarkus.oidc.roles.source=accesstoken),则会验证它。
3.2.3.2. 令牌内省和 UserInfo 缓存 复制链接链接已复制到粘贴板!
代码流访问令牌不会被内省,除非它们应当是角色的来源。但是,它们将用于获取 UserInfo。如果令牌内省、UserInfo 或两者都需要,则需要一个或多个带有代码流访问令牌的远程调用。
有关使用默认令牌缓存或注册自定义缓存实现的更多信息,请参阅 令牌内省和用户Info 缓存。
3.2.3.3. JSON Web 令牌声明验证 复制链接链接已复制到粘贴板!
有关声明验证的详情,包括 iss (issuer)声明,请参阅 JSON Web 令牌声明验证 部分。如果 web-app 应用请求访问令牌验证,它适用于 ID 令牌以及 JWT 格式的访问令牌验证。
3.2.3.4. 进一步安全性,包括代码交换的证明密钥(PKCE) 复制链接链接已复制到粘贴板!
代码 交换的证明密钥 (PKCE)可最大程度降低授权代码拦截器的风险。
虽然 PKCE 是公共 OIDC 客户端的主要重要性,如在浏览器中运行的 SPA 脚本,但它还可以提供对 Quarkus OIDC web-app 应用程序的额外保护。使用 PKCE 时,Quarkus OIDC web-app 应用程序充当机密 OIDC 客户端,这些客户端可以安全地存储客户端 secret,并使用它来交换令牌的代码。
您可以使用 quarkus.oidc.authentication.pkce-required 属性和 32 个字符的 secret 为 OIDC web-app 端点启用 PKCE 代码验证器,如下例所示:
quarkus.oidc.authentication.pkce-required=true quarkus.oidc.authentication.state-secret=eUk1p7UB3nFiXZGUXi0uph1Y9p34YhBU
quarkus.oidc.authentication.pkce-required=true
quarkus.oidc.authentication.state-secret=eUk1p7UB3nFiXZGUXi0uph1Y9p34YhBU
如果您已有 32 个字符的客户端 secret,则不需要设置 quarkus.oidc.authentication.pkce-secret 属性,除非您更喜欢使用不同的 secret 密钥。如果没有配置此 secret,且在客户端 secret 小于 16 个字符时,无法自动生成此 secret。
当用户使用 code_challenge 查询参数重定向到 OIDC 供应商时,需要加密随机生成的 PKCE code_verifier。当用户重定向到 Quarkus 时,code_verifier 会解密,并发送到令牌端点,代码、客户端 secret 和其他参数来完成代码交换。如果 code_verifier 的 SHA256 摘要与身份验证请求过程中提供的 code_challenge 不匹配,则供应商将失败。
3.2.4. 处理和控制身份验证生命周期 复制链接链接已复制到粘贴板!
身份验证的另一个重要要求是确保会话基于的数据是最新的,而不需要用户为每个请求进行身份验证。在有些情况下,明确请求 logout 事件。使用以下关键点查找保护 Quarkus 应用程序的正确平衡:
3.2.4.1. Cookie 复制链接链接已复制到粘贴板!
OIDC 适配器使用 Cookie 来保留会话、代码流和超时状态。这个状态是控制身份验证数据生命周期的关键元素。
使用 quarkus.oidc.authentication.cookie-path 属性来确保当您访问具有重叠或不同根的受保护的资源时,可以看到相同的 Cookie。例如:
-
/index.htmland/web-app/service -
/web-app/service1and/web-app/service2 -
/web-app1/serviceand/web-app2/service
默认情况下,quarkus.oidc.authentication.cookie-path 被设置为 /,但如果需要,您可以将它改为更具体的路径,例如 /web-app。
要动态设置 Cookie 路径,请配置 quarkus.oidc.authentication.cookie-path-header 属性。设置 quarkus.oidc.authentication.cookie-path-header 属性。例如,要使用 'X-Forwarded-Prefix' HTTP 标头的值动态设置 Cookie 路径,请将 属性配置为 quarkus.oidc.authentication.cookie-path-header=X-Forwarded-Prefix。
如果设置了 quarkus.oidc.authentication.cookie-path-header,但当前请求中没有配置的 HTTP 标头,则会检查 quarkus.oidc.authentication.cookie-path。
如果您的应用程序在多个域中部署,请设置 quarkus.oidc.authentication.cookie-domain 属性,以便会话 Cookie 对所有受保护的 Quarkus 服务可见。例如,如果您在以下两个域中部署了 Quarkus 服务,您必须将 quarkus.oidc.authentication.cookie-domain 属性设置为 company.net :
- https://whatever.wherever.company.net/
- https://another.address.company.net/
3.2.4.2. 会话 Cookie 和默认 TokenStateManager 复制链接链接已复制到粘贴板!
OIDC CodeAuthenticationMechanism 使用默认的 io.quarkus.oidc.TokenStateManager 接口实现,以保留授权代码中返回的 ID、访问和刷新令牌,或在加密会话 Cookie 中刷新授权响应。
它使 Quarkus OIDC 端点完全无状态,建议遵循此策略来实现最佳的可扩展性结果。
有关令牌存储的替代方法,请参阅 Session cookie 和 custom TokenStateManager 部分。这对于那些希望自定义解决方案进行令牌状态管理的理想选择,特别是当标准服务器端存储不符合您的特定要求时。
您可以配置默认的 TokenStateManager,以避免在会话 Cookie 中保存访问令牌,并只保留 ID 和刷新令牌或单个 ID 令牌。
只有在端点需要执行以下操作时才需要访问令牌:
-
检索
UserInfo - 使用这个访问令牌访问下游服务
- 使用与访问令牌关联的角色,这些角色会被默认检查
在这种情况下,使用 quarkus.oidc.token-state-manager.strategy 属性来配置令牌状态策略,如下所示:
| to… | 将属性设置为 … |
|---|---|
| 只保留 ID 和刷新令牌 |
|
| 仅保留 ID 令牌 |
|
如果您所选的会话 Cookie 策略组合了令牌并生成大于 4KB 的大型会话 Cookie 值,则一些浏览器可能无法处理此类 Cookie 大小。当 ID、访问和刷新令牌是 JWT 令牌且所选策略为 keep-all-tokens 时,或者在策略 id-refresh-token 时使用 ID 和刷新令牌会出现这种情况。要临时解决这个问题,您可以设置 quarkus.oidc.token-state-manager.split-tokens=true 来为每个令牌创建一个唯一的会话令牌。
默认 TokenStateManager 会加密令牌,然后再将其存储在会话 Cookie 中。以下示例演示了如何将其配置为分割令牌并加密它们:
令牌加密 secret 必须至少为 32 个字符。如果没有配置此密钥,则 quarkus.oidc.credentials.secret 或 quarkus.oidc.credentials.jwt.secret 将会被哈希来创建加密密钥。
如果 Quarkus 使用以下身份验证方法之一向 OIDC 供应商进行身份验证,请配置 quarkus.oidc.token-state-manager.encryption-secret 属性:
- mTLS
-
private_key_jwt,其中使用私有 RSA 或 EC 密钥为 JWT 令牌签名
否则,会生成一个随机密钥,如果 Quarkus 应用程序在管理请求的多个 pod 在云中运行,则可能会造成问题。
您可以通过设置 quarkus.oidc.token-state-manager.encryption-required=false 来禁用会话 Cookie 中的令牌加密。
3.2.4.3. 会话 Cookie 和自定义 TokenStateManager 复制链接链接已复制到粘贴板!
如果要自定义令牌与会话 Cookie 关联的方式,请将自定义 io.quarkus.oidc.TokenStateManager 实现注册为 @ApplicationScoped CDI bean。
例如,您可能想要将令牌保留在缓存集群中,且只有一个密钥存储在会话 Cookie 中。请注意,如果您需要在多个微服务节点上提供令牌,这种方法可能会带来一些挑战。
以下是一个简单的示例:
有关将令牌存储在加密会话 Cookie 中的默认 TokenStateManager 的详情,请参考 Session cookie 和 default TokenStateManager。
3.2.4.4. 退出和过期 复制链接链接已复制到粘贴板!
身份验证信息过期的方法有两种:令牌过期且没有续订或显式退出操作。
我们从明确注销操作开始。
3.2.4.4.1. user-initiated logout 复制链接链接已复制到粘贴板!
用户可以通过向 Quarkus 端点注销路径发送请求,该路径使用 quarkus.oidc.logout.path 属性来请求注销。例如,如果端点地址为 https://application.com/webapp,并且 quarkus.oidc.logout.path 设置为 /logout,则必须将 logout 请求发送到 https://application.com/webapp/logout。
此注销请求将启动一个 RP-initiated logout。用户将被重定向到 OIDC 供应商以注销,并要求他们确认注销是否确实是正常的。
在注销完成后,用户将返回到端点 post-logout 页面,并且设置了 quarkus.oidc.logout.post-logout-path 属性。例如,如果端点地址为 https://application.com/webapp,并且 quarkus.oidc.logout.post-logout-path 设置为 /signin,则用户将返回到 https://application.com/webapp/signin。https://application.com/webapp/signin 请注意,此 URI 必须注册为 OIDC 供应商中的有效的 post_logout_redirect_uri。
如果设置了 quarkus.oidc.logout.post-logout-path,则会创建一个 q_post_logout cookie,并将匹配的 查询参数添加到注销重定向 URI 中,OIDC 供应商会在注销完成后返回此状态。建议 Quarkus state web-app 应用程序检查 state 查询参数是否与 q_post_logout cookie 的值匹配,例如在 Jakarta REST 过滤器中。
请注意,在使用 OpenID Connect Multi-Tenancy 时,cookie 名称会有所不同。例如,它将被命名为 q_post_logout_tenant_1,用于具有 tenant_1 ID 的租户,以此类推。
以下是如何配置 Quarkus 应用程序以启动注销流程的示例:
您可能还希望将 quarkus.oidc.authentication.cookie-path 设置为对所有应用程序资源通用的路径值,本例中为 /。如需更多信息,请参阅 Cookies 部分。
有些 OIDC 供应商不支持 RP-initiated logout 规格,且不会返回 OpenID Connect 已知的 end_session_endpoint 元数据属性。但是,这不是 Quarkus 的问题,因为此类 OIDC 供应商的特定注销机制仅在如何命名 logout URL 查询参数时有所不同。
根据 RP-initiated logout 规格,quarkus.oidc.logout.post-logout-path 属性表示为 post_logout_redirect_uri 查询参数,它不被不支持此规格的供应商识别。
您可以使用 quarkus.oidc.logout.post-logout-url-param 来临时解决这个问题。您还可以使用 quarkus.oidc.logout.extra-params 添加请求更多注销查询参数。例如,以下是如何使用 Auth0 支持注销:
3.2.4.4.2. back-channel logout 复制链接链接已复制到粘贴板!
OIDC 供应商可以使用身份验证数据强制注销所有应用程序。这称为 back-channel logout。在这种情况下,OIDC 将调用每个应用程序中的一个特定 URL 来触发该退出。
OIDC 供应商使用 Back-channel logout 从当前用户登录的所有应用程序注销,绕过用户代理。
您可以将 Quarkus 配置为支持 Back-channel logout,如下所示:
absolute back-channel logout URL 通过向当前端点 URL 添加 quarkus.oidc.back-channel-logout.path 来计算,例如 http://localhost:8080/back-channel-logout。您需要在 OIDC 供应商的管理控制台中配置此 URL。
如果您的 OIDC 供应商没有在当前注销令牌中设置到期声明,您还需要为退出令牌验证配置令牌 age 属性。例如,设置 quarkus.oidc.token.age=10S,以确保自注销令牌的 iat (在)时间后没有超过 10 秒。
3.2.4.4.3. front-channel logout 复制链接链接已复制到粘贴板!
您可以使用 Front-channel logout 直接从用户代理注销当前用户,例如其浏览器。它与 Back-channel logout 类似,但注销步骤由用户代理(如浏览器)执行,而不是在 OIDC 供应商在后台执行。这个选项很少被使用。
您可以配置 Quarkus 以支持 Front-channel logout,如下所示:
此路径将与当前请求的路径进行比较,如果这些路径匹配,用户将被注销。
3.2.4.4.4. 本地退出 复制链接链接已复制到粘贴板!
User-initiated logout 将从 OIDC 供应商注销用户。如果将其用作单点登录,这可能不是您需要的。例如,如果您的 OIDC 供应商是 Google,您将从 Google 及其服务中登出。相反,用户可能只希望退出该特定应用程序。另一个用例可能是 OIDC 供应商没有注销端点。
通过使用 OidcSession,您可以支持本地注销,这意味着只清除本地会话 cookie,如下例所示:
3.2.4.4.4.1. 使用 OidcSession 进行本地注销 复制链接链接已复制到粘贴板!
io.quarkus.oidc.OidcSession 是当前 IdToken 的打包程序,可帮助执行 本地注销,检索当前会话的租户标识符,并检查会话何时过期。随着时间的推移,将向它添加更有用的方法。
3.2.4.5. 会话管理 复制链接链接已复制到粘贴板!
默认情况下,注销基于 OIDC 供应商发布的 ID 令牌的过期时间。当 ID 令牌过期时,Quarkus 端点中的当前用户会话无效,用户会被重新重定向到 OIDC 供应商以进行身份验证。如果 OIDC 供应商中的会话仍然处于活跃状态,则用户会自动重新验证,而无需再次提供其凭证。
通过启用 quarkus.oidc.token.refresh-expired 属性,可以自动扩展当前用户会话。如果设置为 true,当当前 ID 令牌过期时,将使用刷新令牌授权来刷新 ID 令牌,以及访问和刷新令牌。
如果您有一个 用于服务应用程序的单个页面应用程序,您的 OIDC 供应商脚本(如 keycloak.js )正在管理授权代码流,则该脚本也会控制 SPA 身份验证会话生命周期。
如果您使用 Quarkus OIDC web-app 应用程序,则 Quarkus OIDC 代码身份验证机制管理用户会话生命周期。
要使用刷新令牌,您应该仔细配置会话 Cookie 年龄。会话年龄应超过 ID 令牌寿命,并且接近或等于刷新令牌生命周期。
您可以通过添加当前 ID 令牌的 lifespan 值以及 quarkus.oidc. authentication.session-age-extension 和 属性的值来计算会话年龄。
quarkus.oidc.token.lifespan-grace
如果需要,只使用 quarkus.oidc.authentication.session-age-extension 属性来显著扩展会话生命周期。您可以使用 quarkus.oidc.token.lifespan-grace 属性来考虑一些小时钟偏移。
当当前经过身份验证的用户返回到受保护的 Quarkus 端点并且与会话 Cookie 关联的 ID 令牌已过期时,默认情况下,用户会自动重定向到 OIDC Authorization 端点来重新验证。如果用户和此 OIDC 供应商间的会话仍然活跃,OIDC 供应商可能会再次挑战用户,如果会话配置为最后的时间超过 ID 令牌,则可能会出现这种情况。
如果 quarkus.oidc.token.refresh-expired 设为 true,则使用返回初始授权代码的刷新令牌刷新过期的 ID 令牌(和访问令牌)。此刷新令牌也可能被回收(刷新)本身作为此过程的一部分。因此,会创建新的会话 Cookie,会话会被扩展。
在用户未激活的情况下,您可以使用 quarkus.oidc.authentication.session-age-extension 属性来帮助处理过期的 ID 令牌。如果 ID 令牌过期,则会话 Cookie 可能不会在下一个用户请求期间返回到 Quarkus 端点,因为 Cookie 生命周期已过。Quarkus 假设此请求是第一个身份验证请求。将 quarkus.oidc.authentication.session-age-extension 设置为您的裸机用户,并根据您的安全策略。
您可以进一步进入一个步骤,并主动刷新 ID 令牌或访问令牌过期。将 quarkus.oidc.token.refresh-token-time-skew 设置为您要预计刷新的值。如果在当前用户请求过程中,计算当前 ID 令牌将在此 quarkus.oidc.token.refresh-token-time-skew 中过期,然后被刷新,并创建新的会话 cookie。此属性应设置为小于 ID 令牌生命周期的值;更接近这个生命周期值,ID 令牌会被刷新的频率。
您可以通过具有简单的 JavaScript 功能定期 ping Quarkus 端点来进一步优化这个过程,以模拟用户活动,从而减少用户必须重新验证的时间框架。
您无法无限期扩展用户会话。当刷新令牌已过期后,在 OIDC 供应商端点中的返回用户必须在 OIDC 供应商端点中重新进行身份验证。
3.2.5. 与 GitHub 和非OIDC OAuth2 供应商集成 复制链接链接已复制到粘贴板!
GitHub 或 LinkedIn 等一些已知的供应商不是 OpenID Connect 供应商,但支持 授权代码流的 OAuth2 供应商。例如,GitHub OAuth2 和 LinkedIn OAuth2。请记住,OIDC 基于 OAuth2 构建。
OIDC 和 OAuth2 供应商的主要区别在于,除了标准授权代码流 访问和 刷新 OAuth2 供应商返回的令牌外,OIDC 供应商还会返回一个代表用户身份验证的 ID 令牌。
GitHub 等 OAuth2 提供程序不返回 IdToken,用户身份验证是隐式的,间接由 访问令牌 表示。此 访问令牌 代表了一个经过身份验证的用户,授权当前的 Quarkus web-app 应用代表经过身份验证的用户访问某些数据。
对于 OIDC,您可以将 ID 令牌验证为身份验证的有效性,而在 OAuth2 时验证访问令牌。这随后通过调用需要访问令牌的端点,并且通常会返回用户信息来完成。这个方法与 OIDC UserInfo 方法类似,代表 Quarkus OIDC 获取的 UserInfo。
例如,在使用 GitHub 时,Quarkus 端点可以 获取访问令牌,它允许 Quarkus 端点为当前用户请求 GitHub 配置集。
要支持与这样的 OAuth2 服务器的集成,quarkus-oidc 需要以不同的方式配置,以允许在没有 IdToken:quarkus.oidc.authentication.id-token-required=false 的情况下配置授权代码流响应。
虽然您要将扩展配置为支持没有 IdToken 的授权代码流,但会生成内部 IdToken 来标准化 quarkus-oidc 操作的方式。您可以使用 IdToken 支持身份验证会话,并避免在每个请求上将用户重定向到供应商,如 GitHub。在这种情况下,会话寿命被设置为 5 分钟,您可以进一步进行扩展,如 会话管理 部分中所述。
这简化了如何处理支持多个 OIDC 供应商的应用程序。
下一步是确保返回的访问令牌很有用,并且对当前 Quarkus 端点有效。第一种方法是,如果提供商提供了这样的端点,则通过配置 quarkus.oidc.introspection-path 来调用 OAuth2 提供程序内省端点。在这种情况下,您可以使用 quarkus.oidc.roles.source=accesstoken 将访问令牌用作角色源。如果没有内省端点,您可以尝试从提供程序请求 UserInfo,因为它至少将验证访问令牌。为此,请指定 quarkus.oidc.token.verify-access-token-with-user-info=true。您还需要将 quarkus.oidc.user-info-path 属性设置为 URL 端点,该端点获取用户信息(或访问令牌保护的端点)。对于 GitHub,因为它没有内省端点,需要请求 UserInfo。
需要 UserInfo 涉及在每个请求上进行远程调用。因此,您可能需要考虑缓存 UserInfo 数据。如需更多信息,请参阅"OpenID Connect (OIDC) Bearer 令牌身份验证"指南中的 Token Introspection 和 UserInfo 缓存 部分。
或者,您可能希望请求将 UserInfo 嵌入到内部生成的 IdToken 中,并带有 quarkus.oidc.cache-user-info-in-idtoken=true 属性。这种方法的优点是,默认情况下,不会保留缓存的用户 Info 状态与端点 - 相反,它将存储在会话 Cookie 中。如果 UserInfo 包含敏感数据,您可能还需要考虑加密 IdToken。如需更多信息,请参阅使用 TokenStateManager 加密令牌。
OAuth2 服务器可能不支持已知的配置端点。在这种情况下,您必须禁用发现并配置授权、令牌和内省和 UserInfo 端点路径。
对于知名的 OIDC 或 OAuth2 供应商,如 Apple、Facebook、GitHub、Google、Microsoft、Spotify 和 Artistic,Quarkus 可使用 quarkus.oidc.provider 属性简化应用程序的配置。以下是您可以在创建 GitHub OAuth 应用程序后将 quarkus-oidc 与 GitHub 集成。配置 Quarkus 端点,如下所示:
有关配置其他已知的供应商的更多信息,请参阅 OpenID Connect 供应商。
这是端点所需要的,如这个端点使用 GET http://localhost:8080/github/userinfo 返回当前验证的用户配置集,并将其作为单独的 UserInfo 属性访问:
如果您支持多个社交供应商,它带有 OpenID Connect Multi-Tenancy 的帮助,例如 Google,它是一个 OIDC 供应商,返回 IdToken 和 GitHub,它是一个 OAuth2 供应商,它没有返回 IdToken,只允许访问 UserInfo,然后您可以让端点与 Google 和 GitHub 流注入的 SecurityIdentity 工作。当 GitHub 流处于活跃状态时,需要一个简单的 SecurityIdentity,其中使用内部生成的 IdToken 创建的主体将替换为基于 UserInfo的主体:
现在,当用户使用 Google 或 GitHub 登录应用程序时,以下代码将可以正常工作:
可能更为简单的替代方案是注入 @IdToken JsonWebToken 和 UserInfo,并在处理返回 IdToken 的提供程序时使用 JsonWebToken,并将 UserInfo 与不返回 IdToken 的提供程序一起使用。
您必须确保您在 GitHub OAuth 应用程序配置中输入的回调路径与希望在 GitHub 身份验证和应用程序授权成功后重定向用户的端点路径匹配。在这种情况下,它必须设置为 http:localhost:8080/github/userinfo。
3.2.6. 侦听重要的身份验证事件 复制链接链接已复制到粘贴板!
您可以注册 @ApplicationScoped bean,它将观察重要的 OIDC 身份验证事件。当用户第一次登录时,重新验证或刷新会话时,会更新监听程序。未来可能会报告更多事件。例如:
您可以侦听其他安全事件,如 Security Tips and Tricks 指南中的 Observe security events 部分所述。
3.2.7. 将令牌传播到下游服务 复制链接链接已复制到粘贴板!
有关授权代码流访问令牌传播到下游服务的详情,请参考 Token Propagation 部分。