OpenID Connect (OIDC)客户端和令牌传播
摘要
向红帽构建的 Quarkus 文档提供反馈 复制链接链接已复制到粘贴板!
要报告错误或改进文档,请登录您的红帽 JIRA 帐户并提交问题。如果您没有红帽 JIRA 帐户,系统会提示您创建一个帐户。
流程
- 单击以下链接 来创建 ticket。
- 在 Summary 中输入有关此问题的简单描述。
- 提供有关 描述 中问题或增强功能的详细描述。包括一个 URL,以在文档中发生问题。
- 点 Submit 创建问题并将其路由到适当的文档团队。
第 1 章 OpenID Connect (OIDC)和 OAuth2 客户端和过滤器 复制链接链接已复制到粘贴板!
您可以使用 Quarkus 扩展进行 OpenID Connect 和 OAuth 2.0 访问令牌管理,专注于获取、刷新和传播令牌。
这包括以下内容:
-
使用
quarkus-oidc-client,quarkus-rest-client-oidc-filter和quarkus-resteasy-client-oidc-filter扩展从 OpenID Connect 和 OAuth 2.0 兼容授权服务器(如 Keycloak )获取和刷新访问令牌。 -
使用
quarkus-rest-client-oidc-token-propagation和quarkus-resteasy-client-oidc-token-propagation扩展来传播当前的Bearer或Authorization Code Flow访问令牌。
由这些扩展管理的访问令牌可用作 HTTP 授权持有者令牌来访问远程服务。
另请参阅 OpenID Connect 客户端和令牌传播快速入门。
1.1. OidcClient 复制链接链接已复制到粘贴板!
添加以下依赖项:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client</artifactId>
</dependency>
quarkus-oidc-client 扩展提供 reactive io.quarkus.oidc.client.OidcClient,它可用于使用 SmallRye Mutiny Uni 和 Vert.x WebClient 获取和刷新令牌。
OidcClient 在构建时初始化,使用 IDP 令牌端点 URL,该 URL 可以自动发现或手动配置。OidcClient 使用此端点通过利用令牌授权来获取访问令牌,如 client_credentials 或 password,并使用 refresh_token 授权来刷新令牌。
1.1.1. 令牌端点配置 复制链接链接已复制到粘贴板!
默认情况下,通过将 /.well-known/openid-configuration 路径添加到配置的 quarkus.oidc-client.auth-server-url 来发现令牌端点地址。
例如,给定这个 Keycloak URL:
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus
OidcClient 将发现令牌端点 URL 为 http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens。
或者,如果发现端点不可用,或者您希望在发现端点往返中保存,您可以禁用发现并配置令牌端点地址,并带有相对路径值。例如:
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus quarkus.oidc-client.discovery-enabled=false # Token endpoint: http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens quarkus.oidc-client.token-path=/protocol/openid-connect/tokens
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus
quarkus.oidc-client.discovery-enabled=false
# Token endpoint: http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens
quarkus.oidc-client.token-path=/protocol/openid-connect/tokens
在没有发现的情况下配置令牌端点 URL 的更紧凑方法是将 quarkus.oidc-client.token-path 设置为一个绝对 URL:
quarkus.oidc-client.token-path=http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens
quarkus.oidc-client.token-path=http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens
在这种情况下,不需要设置 quarkus.oidc-client.auth-server-url 和 quarkus.oidc-client.discovery-enabled。
1.1.2. 支持的令牌授予 复制链接链接已复制到粘贴板!
主令牌授予 OidcClient 可用于获取令牌,是 client_credentials (默认) 和密码 授权。
1.1.2.1. 客户端凭证授权 复制链接链接已复制到粘贴板!
以下是如何将 OidcClient 配置为使用 client_credentials 授权:
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
client_credentials 授权允许使用 quarkus.oidc-client.grant-options.client.<param-name>=<value > 为令牌请求设置额外的参数。以下是如何使用 audience 参数设置预期的令牌接收者:
1.1.2.2. 密码授权 复制链接链接已复制到粘贴板!
以下是如何将 OidcClient 配置为使用 密码 授权:
它可以通过使用 quarkus.oidc-client.grant-options.password 配置前缀来进一步自定义,类似于如何自定义客户端凭证授权。
1.1.2.3. 其他授权 复制链接链接已复制到粘贴板!
OidcClient 还可以使用授权来帮助获取令牌,该令牌需要一些无法在配置中捕获的额外输入参数。这些授权是 refresh_token (使用外部刷新令牌)、authorization_code 和两个授权来交换当前访问令牌,即 urn:ietf:params:oauth:grant-type:token-exchange 和 urn:ietf:params:oauth:grant-type:jwt-bearer。
如果您需要获取访问令牌,并将现有的刷新令牌发布到当前 Quarkus 端点,则必须使用 refresh_token 授权。此授权使用带外刷新令牌来获取新令牌集。在这种情况下,按如下所示配置 OidcClient :
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.secret=secret quarkus.oidc-client.grant.type=refresh
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=refresh
然后,您可以使用 OidcClient.refreshTokens 方法提供的刷新令牌来获取访问令牌。
使用 urn:ietf:params:oauth:grant-type:token-exchange 或 urn:ietf:params:oauth:grant-type:jwt-bearer 授权,如果您要构建复杂的微服务应用,并希望避免了多个服务被传播到并使用相同的 Bearer 令牌。如需了解更多详细信息,请参阅 Quarkus REST 和 Token Propagation for RESTEasy Classic 的令牌传播。
如果出于某种原因,可能需要使用 OidcClient 支持 授权代码授权,因此您无法使用 Quarkus OIDC 扩展 来支持授权代码流。如果您实现授权代码流有很好的原因,您可以配置 OidcClient,如下所示:
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.secret=secret quarkus.oidc-client.grant.type=code
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=code
然后,您可以使用 OidcClient.accessTokens 方法接受额外属性映射,并传递当前 代码和 redirect_uri 参数来交换令牌的授权代码。
OidcClient 还支持 urn:openid:params:grant-type:ciba grant:
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.secret=secret quarkus.oidc-client.grant.type=ciba
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=ciba
然后,您可以使用 OidcClient.accessTokens 方法接受额外属性映射,并传递 auth_req_id 参数来交换令牌授权代码。
1.1.2.4. 授权范围 复制链接链接已复制到粘贴板!
您可能需要请求特定的一组范围与发布的访问令牌关联。使用专用的 quarkus.oidc-client.scopes list 属性,例如: quarkus.oidc-client.scopes=email,phone
1.1.3. 直接使用 OidcClient 复制链接链接已复制到粘贴板!
您可以直接使用 OidcClient 获取访问令牌,并将它们设置为 Bearer 方案值。
例如,假设 Quarkus 端点必须访问返回用户名的微服务。首先,创建一个 REST 客户端:
现在,使用 OidcClient 获取令牌并传播令牌:
- 1
io.quarkus.oidc.client.runtime.TokensHelper管理访问令牌获取和刷新。
1.1.4. 注入令牌 复制链接链接已复制到粘贴板!
您可以在内部 注入 使用 OidcClient 的令牌。令牌 可用于获取访问令牌并在需要时刷新它们:
1.1.5. use OidcClients 复制链接链接已复制到粘贴板!
io.quarkus.oidc.client.OidcClients 是 OidcClients 的容器 - 它包括了一个默认的 OidcClient 和 named 客户端,可以配置如下:
quarkus.oidc-client.client-enabled=false quarkus.oidc-client.jwt-secret.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.jwt-secret.client-id=quarkus-app quarkus.oidc-client.jwt-secret.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
quarkus.oidc-client.client-enabled=false
quarkus.oidc-client.jwt-secret.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.jwt-secret.client-id=quarkus-app
quarkus.oidc-client.jwt-secret.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
在这种情况下,默认客户端使用 client-enabled=false 属性被禁用。jwt-secret 客户端可以通过以下方式访问:
- 1
- 请参阅 Use OidcClient directly 部分中的
RestClientWithTokenHeaderParam声明。
如果您也使用 OIDC 多租户,并且每个 OIDC 租户都有自己的关联的 OidcClient,您可以使用 Vert.x RoutingContext tenant-id 属性。例如:
您还可以以编程方式创建新的 OidcClient。例如,假设您必须在启动时创建它:
现在,您可以使用此客户端,如下所示:
- 1
- 请参阅 Use OidcClient directly 部分中的
RestClientWithTokenHeaderParam声明。
1.1.6. 注入名为 OidcClient 和 token 复制链接链接已复制到粘贴板!
如果有多个配置的 OidcClient 对象,您可以通过额外的 qualifier @Named 指定 OidcClient 注入目标,而不是使用 OidcClient OidcClients :
- 1
- 请参阅 Use OidcClient directly 部分中的
RestClientWithTokenHeaderParam声明。
相同的限定符可以用来指定用于令牌注入的 Oidc :
Client
1.1.7. 在 RestClient Reactive ClientFilter 中使用 OidcClient 复制链接链接已复制到粘贴板!
添加以下 Maven 依赖:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-oidc-filter</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-oidc-filter</artifactId>
</dependency>
它还会使 io.quarkus:quarkus-oidc-client。
quarkus-rest-client-oidc-filter 扩展提供 io.quarkus.oidc.client.filter.OidcClientRequestReactiveFilter。
它的工作方式与 OidcClientRequestFilter 的效果类似(请参阅 MicroProfile RestClient 客户端过滤器 中的 OidcClient)- 它使用 OidcClient 获取访问令牌,根据需要刷新该访问令牌,并将它设置为 HTTP Authorization Bearer 方案值。区别在于,它与 Reactive RestClient 配合使用,并实施非阻塞客户端过滤器,在获取或刷新令牌时不会阻断当前的 IO 线程。
OidcClientRequestReactiveFilter 延迟初始令牌获取,直到执行前,以避免阻塞 IO 线程。
您可以使用 io.quarkus.oidc.reactive.filter.OidcClientFilter 或 注解来选择性地注册 org.eclipse.microprofile. rest.client.annotation.RegisterProviderOidcClientRequestReactiveFilter :
or
OidcClientRequestReactiveFilter 默认使用默认的 OidcClient。可以使用 quarkus.rest-client-oidc-filter.client-name 配置属性来选择命名的 OidcClient。您还可以通过设置 @ 注释的 OidcClient Filtervalue 属性来选择 OidcClient。通过注解设置的客户端名称的优先级高于 quarkus.rest-client-oidc-filter.client-name 配置属性。例如,假设 这个 jwt-secret 名为 OIDC 客户端声明,您可以引用此客户端,如下所示:
1.1.8. 在 RestClient ClientFilter 中使用 OidcClient 复制链接链接已复制到粘贴板!
添加以下 Maven 依赖:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-client-oidc-filter</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-client-oidc-filter</artifactId>
</dependency>
它还会使 io.quarkus:quarkus-oidc-client。
quarkus-resteasy-client-oidc-filter 扩展提供 io.quarkus.oidc.client.filter.OidcClientRequestFilter Jakarta REST ClientRequestFilter,它使用 OidcClient 获取访问令牌,根据需要刷新它,并将其设置为 HTTP Authorization Bearer 方案值。
默认情况下,此过滤器将获取 OidcClient,以便在初始化时获取第一对访问和刷新令牌。如果访问令牌短且刷新令牌不可用,则令牌获取应该会延迟为 quarkus.oidc-client.early-tokens-acquisition=false。
您可以使用 io.quarkus.oidc.client.filter.OidcClientFilter 或 org.eclipse.microprofile.rest.client.annotation.RegisterProvider 注解来选择性地注册 OidcClientRequestFilter :
or
另外,如果设置了 quarkus.resteasy-client-oidc-filter.register-filter.register-filter=true 属性,OidcClientRequestFilter 可以自动注册到所有 MP Rest 或 Jakarta REST 客户端。
OidcClientRequestFilter 默认使用默认的 OidcClient。可以使用 quarkus.resteasy-client-oidc-filter.client-name 配置属性来选择命名的 OidcClient。您还可以通过设置 @ 注释的 OidcClient Filtervalue 属性来选择 OidcClient。通过注解设置的客户端名称的优先级高于 quarkus.resteasy-client-oidc-filter.client-name 配置属性。例如,假设 这个 jwt-secret 名为 OIDC 客户端声明,您可以引用此客户端,如下所示:
1.1.9. 使用自定义 RestClient ClientFilter 复制链接链接已复制到粘贴板!
如果您愿意,您可以使用自己的自定义过滤器并注入 Tokens :
Tokens 生成者将获取并刷新令牌,自定义过滤器将决定如何使用令牌。
您还可以注入命名的 Tokens,请参阅名为 OidcClient 和 Tokens 的 Inject
1.1.10. 刷新访问令牌 复制链接链接已复制到粘贴板!
OidcClientRequestReactiveFilter、OidcClientRequestFilter 和 Tokens producers 将刷新当前的过期访问令牌(如果刷新令牌可用)。另外,quarkus.oidc-client.refresh-token-time-skew 属性可用于抢占访问令牌刷新,以避免发送可能导致 HTTP 401 错误的几乎过期的访问令牌。例如,如果此属性设置为 3S,并且访问令牌将在 3 秒内过期,则此令牌将被自动刷新。
如果需要刷新访问令牌,但没有提供刷新令牌,则会尝试使用配置的授权(如 client_credentials )获取新令牌。
有些 OpenID Connect 供应商不会在 client_credentials 授权响应中返回刷新令牌。例如,从 Keycloak 12 开始,client_credentials 默认不会返回刷新令牌。供应商也可以限制使用刷新令牌的次数。
1.1.11. 撤销访问令牌 复制链接链接已复制到粘贴板!
如果您的 OpenId Connect 供应商(如 Keycloak)支持令牌撤销端点,则使用 OidcClient SerialrevokeAccessToken 来撤销当前的访问令牌。吊销端点 URL 与令牌请求 URI 一起发现,也可以使用 quarkus.oidc-client.revoke-path 配置。
如果将此令牌与 REST 客户端搭配使用,或者访问令牌已用于很长时间且您要刷新它,您可能希望撤销访问令牌。
这可以通过使用刷新令牌请求令牌刷新来实现。但是,如果刷新令牌不可用,您可以首先撤销它,然后请求新的访问令牌来刷新它。
1.1.12. OidcClient 身份验证 复制链接链接已复制到粘贴板!
OidcClient 必须向 OpenID Connect Provider 进行身份验证,以便 client_credentials 和其他授权请求成功。所有 OIDC 客户端身份验证 选项都被支持,例如:
client_secret_basic:
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.secret=mysecret
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=mysecret
or
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.client-secret.value=mysecret
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.client-secret.value=mysecret
或者,使用从 CredentialsProvider 检索的 secret:
client_secret_post:
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.client-secret.value=mysecret quarkus.oidc-client.credentials.client-secret.method=post
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.client-secret.value=mysecret
quarkus.oidc-client.credentials.client-secret.method=post
client_secret_jwt,签名算法是 HS256 :
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
或者,使用从 CredentialsProvider 检索的 secret,签名算法为 HS256 :
private_key_jwt,带有内嵌在 application.properties 中的 PEM 密钥,签名算法为 RS256 :
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.jwt.key=Base64-encoded private key representation
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.key=Base64-encoded private key representation
private_key_jwt 使用 PEM 密钥文件,签名算法为 RS256 :
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/ quarkus.oidc-client.client-id=quarkus-app quarkus.oidc-client.credentials.jwt.key-file=privateKey.pem
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.key-file=privateKey.pem
private_key_jwt 带有密钥存储文件,签名算法为 RS256 :
使用 client_secret_jwt 或 private_key_jwt 身份验证方法可确保没有客户端 secret overwire。
1.1.12.1. 其他 JWT 身份验证选项 复制链接链接已复制到粘贴板!
如果使用 client_secret_jwt 或 private_key_jwt 身份验证方法,则可以自定义 JWT 签名算法、密钥标识符、audience、subject 和 issuer,例如:
1.1.12.2. JWT Bearer 复制链接链接已复制到粘贴板!
RFC7523 解释了如何使用 JWT Bearer 令牌对客户端进行身份验证,请参阅 使用 JWT 进行客户端身份验证 部分。
它可以启用,如下所示:
quarkus.oidc-client.auth-server-url=${auth-server-url}
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.source=bearer
quarkus.oidc-client.auth-server-url=${auth-server-url}
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.source=bearer
接下来,JWT bearer 令牌必须作为 client_assertion 参数提供给 OIDC 客户端。
您可以使用 OidcClient 方法获取或刷新接受额外授权参数的令牌,例如 oidcClient.getTokens (Map.of ("client_assertion", "ey…")。
如果使用 OIDC 客户端过滤器,则必须注册将提供此断言的自定义过滤器。
以下是 Quarkus REST (以前称为 RESTEasy Reactive)自定义过滤器的示例:
以下是 RESTEasy Classic 自定义过滤器的示例:
1.1.12.3. Apple POST JWT 复制链接链接已复制到粘贴板!
Apple OpenID Connect Provider 使用 client_secret_post 方法,其中 secret 是使用 private_key_jwt 身份验证方法生成的 JWT,但使用 Apple 帐户特定的签发者和主题属性。
quarkus-oidc-client 支持非标准 client_secret_post_jwt 身份验证方法,它可以配置如下:
1.1.12.4. 双向 TLS 复制链接链接已复制到粘贴板!
有些 OpenID Connect 提供者要求客户端作为 mutual TLS (mTLS)身份验证过程的一部分进行身份验证。
quarkus-oidc-client 可以配置如下,以支持 mTLS :
1.1.13. 测试 复制链接链接已复制到粘贴板!
首先,将以下依赖项添加到 test 项目中:
1.1.13.1. Wiremock 复制链接链接已复制到粘贴板!
在您的测试项目中添加以下依赖项:
- 1
- 使用正确的 Wiremock 版本。可在此找到所有可用版本。https://search.maven.org/artifact/org.wiremock/wiremock
编写基于 Wiremock 的 QuarkusTestResourceLifecycleManager,例如:
准备 REST 测试端点。您可以使用注入的 MP REST 客户端和注册的 OidcClient 过滤器测试前端端点,调用下游端点。此端点将令牌回显。例如,请参阅 主 Quarkus 存储库中的 integration-tests/oidc-client-wiremock。
设置 application.properties,例如:
最后,编写测试代码。根据上面的基于 Wiremock 的资源,第一次测试调用应返回 access_token_1 访问令牌,该令牌将在 4 秒后过期。使用 等待 静默等待大约 5 秒,现在下一个测试调用应返回 access_token_2 访问令牌,该令牌确认已过期的 access_token_1 访问令牌已被刷新。
1.1.13.2. Keycloak 复制链接链接已复制到粘贴板!
如果使用 Keycloak,您可以使用 OpenID Connect Bearer Token Integration Keycloak 部分中描述的相同方法。
1.1.14. 如何检查日志中的错误 复制链接链接已复制到粘贴板!
启用 io.quarkus.oidc.client.runtime.OidcClientImpl TRACE 级别日志记录,以查看令牌获取和刷新错误的更多详情:
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".level=TRACE quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".min-level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".min-level=TRACE
启用 io.quarkus.oidc.client.runtime.OidcClientRecorder TRACE 级别日志记录,以查看 OidcClient 初始化错误的更多详情:
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".level=TRACE quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".min-level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".min-level=TRACE
1.2. OIDC 请求过滤器 复制链接链接已复制到粘贴板!
您可以通过注册一个或多个 OidcRequestFilter 实现(可以更新或添加新的请求标头)来过滤 Quarkus 向 OIDC 供应商发出的 OIDC 请求。例如,过滤器可以分析请求正文,并将其摘要添加为新的标头值:
1.3. Quarkus REST 的令牌传播 复制链接链接已复制到粘贴板!
quarkus-rest-client-oidc-token-propagation 扩展提供了一个 REST 客户端过滤器 io.quarkus.oidc.token.propagation.reactive.AccessTokenRequestReactiveFilter,它简化了身份验证信息的传播。此客户端传播当前活动请求中存在的 bearer 令牌,或作为 HTTP Authorization 标头的 Bearer 方案值从 授权代码流机制 获取的令牌。
您可以使用 io.quarkus.oidc.token.propagation.AccessToken 或 org.eclipse.microprofile.rest.client.annotation.RegisterProvider 注解来选择性地注册 AccessTokenRequestReactiveFilter,例如:
or
另外,AccessTokenRequestReactiveFilter 可以支持在传播令牌前交换令牌的复杂应用程序。
如果您使用 Keycloak 或其他支持 Token Exchange 令牌授权的 OIDC 供应商,您可以配置 AccessTokenRequestReactiveFilter 来交换令牌,如下所示:
- 1
- 请注意,当 OidcClient 名称使用
io.quarkus.oidc.token.propagation.AccessToken#exchangeTokenClient注解属性设置时,会忽略exchange-token配置属性。
AccessTokenRequestReactiveFilter 将使用 OidcClient 来交换当前令牌,您可以使用 quarkus.oidc-client.grant-options.exchange 设置 OpenID Connect 提供程序期望的额外交换属性。
如果您使用需要使用 JWT bearer 令牌 授权的 Azure 等提供程序来交换当前令牌,您可以配置 AccessTokenRequestReactiveFilter 来交换令牌,如下所示:
AccessTokenRequestReactiveFilter 默认使用默认的 OidcClient。可以使用 quarkus.rest-client-oidc-token-propagation.client-name 配置属性或 io.quarkus.oidc.token.propagation.AccessToken#exchangeTokenClient 注解属性来选择命名的 OidcClient。
1.4. RESTEasy Classic 的令牌传播 复制链接链接已复制到粘贴板!
quarkus-resteasy-client-oidc-token-propagation 扩展提供了两个 Jakarta REST jakarta.ws.rs.client.ClientRequestFilter 类实现,以简化身份验证信息的传播。io.quarkus.oidc.token.propagation.AccessTokenRequestFilter 传播在当前活动请求中的 Bearer 令牌,或从 Authorization 代码流机制获取的令牌,作为 HTTP Authorization 标头的 Bearer 方案值。io.quarkus.oidc.token.propagation.JsonWebTokenRequestFilter 提供相同的功能,但也提供对 JWT 令牌的支持。
当您需要传播当前的授权代码流访问令牌时,直接令牌传播将正常工作,因为代码流访问令牌(而不是 ID 令牌)旨在为当前的 Quarkus 端点传播,以代表当前经过身份验证的用户访问远程服务。
但是,应避免直接端到端的 Bearer 令牌传播。例如,Client → Service A → Service B,其中 Service B 接收由 Client 发送到 Service A 的令牌。在这种情况下,Service B 无法区分令牌是否来自 Service A 或直接与 客户端。对于 Service B 验证令牌来自 Service A,它应该能够断言新的签发者和受众声明。
此外,复杂的应用可能需要在传播令牌之前交换或更新令牌。例如,当 Service A 访问 Service B 时,访问上下文可能会有所不同。在这种情况下,服务 A 可能会被授予一个范围范围,或者完全不同的范围来访问服务 B。
以下小节演示了 AccessTokenRequestFilter 和 JsonWebTokenRequestFilter 可以如何提供帮助。
1.4.1. RestClient AccessTokenRequestFilter 复制链接链接已复制到粘贴板!
AccessTokenRequestFilter 将所有令牌视为 Strings,因此它可以使用 JWT 和 opaque 令牌。
您可以使用 io.quarkus.oidc.token.propagation.AccessToken 或 org.eclipse.microprofile.rest.client.annotation.RegisterProvider 来选择性地注册 AccessTokenRequestFilter,例如:
or
另外,如果 quarkus.resteasy-client-oidc-token-propagation.register-filter 属性设置为 true,并且 quarkus.resteasy-client-oidc-token-propagation.json-web-token 属性设置为 false,则 AccessTokenRequestFilter 属性会自动注册到所有 MP Rest 或 Jakarta REST 客户端。
1.4.1.1. 在传播前交换令牌 复制链接链接已复制到粘贴板!
如果需要在传播前交换当前的访问令牌,并使用 Keycloak 或其他支持 Token Exchange 令牌授权的 OpenID Connect 供应商,您可以配置 AccessTokenRequestFilter,如下所示:
如果您使用需要使用 JWT bearer 令牌 授权的 Azure 等提供程序来交换当前令牌,您可以配置 AccessTokenRequestFilter 以交换令牌,如下所示:
AccessTokenRequestFilter 将使用 OidcClient 来交换当前令牌,您可以使用 quarkus.oidc-client.grant-options.exchange 设置 OpenID Connect 提供程序期望的额外交换属性。
AccessTokenRequestFilter 默认使用 OidcClient。可以使用 quarkus.resteasy-client-oidc-token-propagation.client-name 配置属性来选择命名的 OidcClient。
1.4.2. RestClient JsonWebTokenRequestFilter 复制链接链接已复制到粘贴板!
如果使用 Bearer JWT 令牌,则建议使用 JsonWebTokenRequestFilter,其中这些令牌可以具有其声明,如 签发者 和 使用者 修改,以及再次修改更新的令牌(如重新签名)。它需要一个注入的 org.eclipse.microprofile.jwt.JsonWebToken,因此无法使用不透明令牌。另外,如果您的 OpenID Connect Provider 支持 Token Exchange 协议,则建议使用 AccessTokenRequestFilter,因为 JWT 和不透明 bearer 令牌都可以安全地与 AccessTokenRequestFilter 交换。
JsonWebTokenRequestFilter 可使 Service A 实施轻松更新注入的 org.eclipse.microprofile.jwt.WebToken 及新的 签发者 和 audience 声明值,并使用新的签名再次保护更新的令牌。唯一的困难是确保服务 A 具有从安全文件系统或远程安全存储(如 Vault)置备的签名密钥。
您可以使用 io.quarkus.oidc.token.propagation.JsonWebToken 或 org.eclipse.microprofile.rest.client.annotation.RegisterProvider 来选择性地注册 JsonWebTokenRequestFilter,例如:
or
另外,如果 quarkus.resteasy-client-oidc-token-propagation.register-filter 和 quarkus.resteasy-client-oidgation.register-filter 和 quarkus.resteasy-client-oidc-token-propagation.json-web-token 属性都会自动注册 JsonWebTokenRequestFilter。
1.4.2.1. 在传播前更新令牌 复制链接链接已复制到粘贴板!
如果注入的令牌需要有其 iss (issuer)或 aud (audience)声明使用新签名再次更新和保护,则可以配置 JsonWebTokenRequestFilter,如下所示:
如前文所述,如果使用 Keycloak 或支持 Token Exchange 协议的 OpenID Connect Provider,请使用 AccessTokenRequestFilter。
1.4.3. 测试 复制链接链接已复制到粘贴板!
您可以生成令牌,如 OpenID Connect Bearer Token Integration 测试 部分中所述。准备 REST 测试端点。您可以使用测试前端端点,它使用注入的 MP REST 客户端和注册的令牌传播过滤器,调用下游端点。例如,请参阅 主 Quarkus 存储库中的 integration-tests/resteasy-client-oidc-token-propagation。
1.5. 配置参考 复制链接链接已复制到粘贴板!
1.5.1. OIDC 客户端 复制链接链接已复制到粘贴板!
build 时修复的 - 配置属性在构建时修复 - 所有其他配置属性在运行时可覆盖
| 配置属性 | 类型 | default |
|
在构建时修复了 如果启用了 OIDC 客户端扩展。
环境变量: | 布尔值 |
|
|
OpenID Connect (OIDC)服务器的基本 URL,例如
环境变量: | string | |
|
发现 OIDC 端点。如果没有启用,您必须单独配置 OIDC 端点 URL。
环境变量: | 布尔值 |
|
|
签发访问和刷新令牌的 OIDC 令牌端点;指定为相对路径或绝对 URL。如果
环境变量: | string | |
|
OIDC 令牌撤销端点的相对路径或绝对路径 URL。
环境变量: | string | |
|
应用程序的客户端 ID。每个应用都有一个客户端 ID,用于标识应用程序。如果
环境变量: | string | |
|
应用的客户端名称。它代表应用程序的人类可读描述,您可以在 OpenId Connect 供应商的仪表板中注册应用程序(客户端)时提供。例如,您可以将此属性设置为具有更详细的日志消息,记录给定客户端的活动。
环境变量: | string | |
|
尝试初始连接到 OIDC 服务器的持续时间。例如,将持续时间设置为
环境变量: | ||
|
如果临时丢失,重试重新建立现有 OIDC 连接的次数。与
环境变量: | int |
|
|
当前 OIDC 连接请求超时的秒数。
环境变量: |
| |
|
是否应该对 worker 线程执行 DNS 查找。当您可以看到由 HTTP 请求到 OIDC 服务器阻止的 Vert.x 事件循环的日志记录警告时,请使用这个选项。
Environment variable: | 布尔值 |
|
|
WebClient 使用的连接池的最大大小。
环境变量: | int | |
|
环境变量: | string | |
|
客户端机密值。如果设置了
环境变量: | string | |
|
CredentialsProvider bean 名称,只有在注册了多个 CredentialsProvider 时才应设置
环境变量: | string | |
|
CredentialsProvider 密钥环名称。只有在使用的 CredentialsProvider 需要密钥环名称来查找 secret 时,才需要密钥环名称,这通常是当一个 CredentialsProvider 被多个扩展共享时,才需要多个扩展从更多动态源(如 vault 实例或 secret manager)检索凭证时。
环境变量: | string | |
|
CredentialsProvider 客户端 secret 密钥
环境变量: | string | |
|
身份验证方法。如果设置了
环境变量: |
基本:
post:
post-jwt: query :客户端 ID 和 secret 作为 HTTP 查询参数提交。这个选项只支持 OIDC 扩展。 | |
|
JWT 令牌源:OIDC 供应商客户端或现有的 JWT bearer 令牌。
环境变量: |
|
|
|
如果提供,则表示 JWT 使用 secret 密钥进行了签名。
环境变量: | string | |
|
CredentialsProvider bean 名称,只有在注册了多个 CredentialsProvider 时才应设置
Environment variable: | string | |
|
CredentialsProvider 密钥环名称。只有在使用的 CredentialsProvider 需要密钥环名称来查找 secret 时,才需要密钥环名称,这通常是当一个 CredentialsProvider 被多个扩展共享时,才需要多个扩展从更多动态源(如 vault 实例或 secret manager)检索凭证时。
环境变量: | string | |
|
CredentialsProvider 客户端 secret 密钥
Environment variable: | string | |
|
私钥的字符串表示。如果提供,则表示 JWT 是使用 PEM 或 JWK 格式的私钥签名的。您可以使用
环境变量: | string | |
|
如果提供,则表示 JWT 是使用 PEM 或 JWK 格式的私钥签名的。您可以使用
环境变量: | string | |
|
如果提供,则表示 JWT 使用密钥存储中的私钥签名。
环境变量: | string | |
|
指定密钥存储文件的密码的参数。
环境变量: | string | |
|
私钥 ID 或别名。
环境变量: | string | |
|
私钥密码。
环境变量: | string | |
|
JWT 受众(u
环境变量: | string | |
|
添加为 JWT
环境变量: | string | |
|
添加为 JWT 的签名密钥的签发者
环境变量: | string | |
|
添加为 JWT
环境变量: | string | |
|
其他声明.
环境变量: | Map<String,String> | |
|
用于
环境变量: | string | |
|
JWT 生命周期(以秒为单位)。这个值添加到发出 JWT 的时间,以计算过期时间。
环境变量: | int |
|
|
如果为 true,则客户端身份验证令牌是 JWT bearer 授权断言。不生成 'client_assertion' 和 'client_assertion_type' 表单属性,而是只生成 'assertion'。这个选项只支持 OIDC 客户端扩展。
环境变量: | 布尔值 |
|
|
代理的主机名或 IP 地址。
环境变量: | string | |
|
代理的端口号。默认值为
环境变量: | int |
|
|
如果代理需要身份验证,则用户名。
环境变量: | string | |
|
如果代理需要身份验证,则密码。
环境变量: | string | |
|
证书验证和主机名验证,可以是以下
环境变量: | 必需 :证书会被验证,并且启用了主机名验证。这是默认值。 certificate-validation :证书会被验证,但禁用主机名验证。 none :所有证书都是可信的,主机名验证被禁用。 | |
|
保存证书信息的可选密钥存储,而不是指定单独的文件。
环境变量: | path | |
|
密钥存储文件的类型。如果未指定,则根据文件名自动检测到类型。
环境变量: | string | |
|
密钥存储文件的提供程序。如果未指定,则根据密钥存储文件类型自动检测到该提供程序。
环境变量: | string | |
|
密钥存储文件的密码。如果未指定,则使用默认值,即
环境变量: | string | |
|
密钥存储中特定密钥的别名。禁用 SNI 时,如果密钥存储包含多个密钥且没有指定别名,则行为未定义。
环境变量: | string | |
|
密钥的密码(如果与
环境变量: | string | |
|
保存要信任的证书信息的信任存储。
环境变量: | path | |
|
truststore 文件的密码。
环境变量: | string | |
|
信任存储证书的别名。
环境变量: | string | |
|
truststore 文件的类型。如果未指定,则根据文件名自动检测到类型。
环境变量: | string | |
|
truststore 文件的供应商。如果没有提供,则会根据信任存储文件类型自动检测到供应商。
环境变量: | string | |
|
唯一的 OIDC 客户端标识符。它必须在 OIDC 客户端动态创建时设置,并在所有其他情况下是可选的。
环境变量: | string | |
|
如果启用了此客户端配置。
环境变量: | 布尔值 |
|
|
访问令牌范围列表
环境变量: | 字符串列表 | |
|
刷新令牌时间偏移(以秒为单位)。如果启用了此属性,则在检查是否应刷新访问令牌时,配置的秒数会添加到当前时间。如果总和超过此访问令牌的过期时间,则会进行刷新。
Environment variable: | ||
|
如果访问令牌 'expires_in' 属性应检查为绝对时间值,而不是相对于当前时间的持续时间。
环境变量: | 布尔值 |
|
|
授权类型
环境变量: | Client: 'client_credentials' 授权只需要 OIDC 客户端身份验证 Password: 'password' 授权需要 OIDC 客户端和用户('username' 和 'password')身份验证 Code: 'authorization_code' 授权需要 OIDC 客户端身份验证,以及至少 'code' 和 'redirect_uri' 参数,它们必须在令牌请求时传递给 OidcClient。 Exchange: 'urn:ietf:params:oauth:grant-type:token-exchange' 授权需要 OIDC 客户端身份验证,以及至少 'subject_token' 参数,该参数必须在令牌请求时传递给 OidcClient。 JWT: 'urn:ietf:params:oauth:grant-type:jwt-bearer' 授权需要 OIDC 客户端身份验证,以及至少一个 'assertion' 参数,该参数必须在令牌请求时传递给 OidcClient。
refresh: 'refresh_token' 授权需要 OIDC 客户端身份验证和刷新令牌。请注意,如果访问令牌获取响应包含刷新令牌,OidcClient 默认支持此授权。然而,在某些情况下,会提供带外的刷新令牌,例如,它可以在多个机密客户端的服务之间共享,等等。如果 'quarkus.oidc-client.grant-type' 设置为 'refresh',则 ciba: 'urn:openid:params:grant-type:ciba' 授权需要 OIDC 客户端身份验证,以及 'auth_req_id' 参数,该参数必须在令牌请求时传递给 OidcClient。 device: 'urn:ietf:params:oauth:grant-type:device_code' 授权需要 OIDC 客户端身份验证,以及 'device_code' 参数,该参数必须在令牌请求时传递给 OidcClient。 | client |
|
令牌授权响应中的访问令牌属性名称
环境变量: | string |
|
|
在令牌授权响应中刷新令牌属性名称
环境变量: | string |
|
|
令牌授权响应中的访问令牌到期属性名称
环境变量: | string |
|
|
在令牌授权响应中刷新令牌到期属性名称
环境变量: | string |
|
|
授权选项
环境变量: | Map<String,Map<String,String>> | |
|
要求所有使用"OidcClient"的过滤器在后结构初始化时获取令牌,在使用这些令牌之前可能会比较长。如果访问令牌在第一次使用并且没有刷新令牌可用之前过期,则应禁用此属性。
环境变量: | 布尔值 |
|
|
必须发送到令牌端点的自定义 HTTP 标头
环境变量: | Map<String,String> | |
| 类型 | default | |
|
OpenID Connect (OIDC)服务器的基本 URL,例如
环境变量: | string | |
|
发现 OIDC 端点。如果没有启用,您必须单独配置 OIDC 端点 URL。
环境变量: | 布尔值 |
|
|
签发访问和刷新令牌的 OIDC 令牌端点;指定为相对路径或绝对 URL。如果
环境变量: | string | |
|
OIDC 令牌撤销端点的相对路径或绝对路径 URL。
环境变量: | string | |
|
应用程序的客户端 ID。每个应用都有一个客户端 ID,用于标识应用程序。如果
环境变量: | string | |
|
应用的客户端名称。它代表应用程序的人类可读描述,您可以在 OpenId Connect 供应商的仪表板中注册应用程序(客户端)时提供。例如,您可以将此属性设置为具有更详细的日志消息,记录给定客户端的活动。
环境变量: | string | |
|
尝试初始连接到 OIDC 服务器的持续时间。例如,将持续时间设置为
环境变量: | ||
|
如果临时丢失,重试重新建立现有 OIDC 连接的次数。与
环境变量: | int |
|
|
当前 OIDC 连接请求超时的秒数。
环境变量: |
| |
|
是否应该对 worker 线程执行 DNS 查找。当您可以看到由 HTTP 请求到 OIDC 服务器阻止的 Vert.x 事件循环的日志记录警告时,请使用这个选项。
Environment variable: | 布尔值 |
|
|
WebClient 使用的连接池的最大大小。
环境变量: | int | |
|
环境变量: | string | |
|
客户端机密值。如果设置了
环境变量: | string | |
|
CredentialsProvider bean 名称,只有在注册了多个 CredentialsProvider 时才应设置
环境变量: | string | |
|
CredentialsProvider 密钥环名称。只有在使用的 CredentialsProvider 需要密钥环名称来查找 secret 时,才需要密钥环名称,这通常是当一个 CredentialsProvider 被多个扩展共享时,才需要多个扩展从更多动态源(如 vault 实例或 secret manager)检索凭证时。
环境变量: | string | |
|
CredentialsProvider 客户端 secret 密钥
环境变量: | string | |
|
身份验证方法。如果设置了
环境变量: |
基本:
post:
post-jwt: query :客户端 ID 和 secret 作为 HTTP 查询参数提交。这个选项只支持 OIDC 扩展。 | |
|
JWT 令牌源:OIDC 供应商客户端或现有的 JWT bearer 令牌。
Environment variable: |
|
|
|
如果提供,则表示 JWT 使用 secret 密钥进行了签名。
环境变量: | string | |
|
CredentialsProvider bean 名称,只有在注册了多个 CredentialsProvider 时才应设置
Environment variable: | string | |
|
CredentialsProvider 密钥环名称。只有在使用的 CredentialsProvider 需要密钥环名称来查找 secret 时,才需要密钥环名称,这通常是当一个 CredentialsProvider 被多个扩展共享时,才需要多个扩展从更多动态源(如 vault 实例或 secret manager)检索凭证时。
Environment variable: | string | |
|
CredentialsProvider 客户端 secret 密钥
Environment variable: | string | |
|
私钥的字符串表示。如果提供,则表示 JWT 是使用 PEM 或 JWK 格式的私钥签名的。您可以使用
环境变量: | string | |
|
如果提供,则表示 JWT 是使用 PEM 或 JWK 格式的私钥签名的。您可以使用
Environment variable: | string | |
|
如果提供,则表示 JWT 使用密钥存储中的私钥签名。
环境变量: | string | |
|
指定密钥存储文件的密码的参数。
环境变量: | string | |
|
私钥 ID 或别名。
Environment variable: | string | |
|
私钥密码。
环境变量: | string | |
|
JWT 受众(u
环境变量: | string | |
|
添加为 JWT
Environment variable: | string | |
|
添加为 JWT 的签名密钥的签发者
环境变量: | string | |
|
添加为 JWT
Environment variable: | string | |
|
其他声明.
环境变量: | Map<String,String> | |
|
用于
环境变量: | string | |
|
JWT 生命周期(以秒为单位)。这个值添加到发出 JWT 的时间,以计算过期时间。
环境变量: | int |
|
|
如果为 true,则客户端身份验证令牌是 JWT bearer 授权断言。不生成 'client_assertion' 和 'client_assertion_type' 表单属性,而是只生成 'assertion'。这个选项只支持 OIDC 客户端扩展。
环境变量: | 布尔值 |
|
|
代理的主机名或 IP 地址。
环境变量: | string | |
|
代理的端口号。默认值为
环境变量: | int |
|
|
如果代理需要身份验证,则用户名。
环境变量: | string | |
|
如果代理需要身份验证,则密码。
环境变量: | string | |
|
证书验证和主机名验证,可以是以下
环境变量: | 必需 :证书会被验证,并且启用了主机名验证。这是默认值。 certificate-validation :证书会被验证,但禁用主机名验证。 none :所有证书都是可信的,主机名验证被禁用。 | |
|
保存证书信息的可选密钥存储,而不是指定单独的文件。
环境变量: | path | |
|
密钥存储文件的类型。如果未指定,则根据文件名自动检测到类型。
环境变量: | string | |
|
密钥存储文件的提供程序。如果未指定,则根据密钥存储文件类型自动检测到该提供程序。
环境变量: | string | |
|
密钥存储文件的密码。如果未指定,则使用默认值,即
环境变量: | string | |
|
密钥存储中特定密钥的别名。禁用 SNI 时,如果密钥存储包含多个密钥且没有指定别名,则行为未定义。
环境变量: | string | |
|
密钥的密码(如果与
环境变量: | string | |
|
保存要信任的证书信息的信任存储。
环境变量: | path | |
|
truststore 文件的密码。
环境变量: | string | |
|
信任存储证书的别名。
环境变量: | string | |
|
truststore 文件的类型。如果未指定,则根据文件名自动检测到类型。
环境变量: | string | |
|
truststore 文件的供应商。如果没有提供,则会根据信任存储文件类型自动检测到供应商。
环境变量: | string | |
|
唯一的 OIDC 客户端标识符。它必须在 OIDC 客户端动态创建时设置,并在所有其他情况下是可选的。
环境变量: | string | |
|
如果启用了此客户端配置。
环境变量: | 布尔值 |
|
|
访问令牌范围列表
环境变量: | 字符串列表 | |
|
刷新令牌时间偏移(以秒为单位)。如果启用了此属性,则在检查是否应刷新访问令牌时,配置的秒数会添加到当前时间。如果总和超过此访问令牌的过期时间,则会进行刷新。
环境变量: | ||
|
如果访问令牌 'expires_in' 属性应检查为绝对时间值,而不是相对于当前时间的持续时间。
环境变量: | 布尔值 |
|
|
授权类型
环境变量: | Client: 'client_credentials' 授权只需要 OIDC 客户端身份验证 Password: 'password' 授权需要 OIDC 客户端和用户('username' 和 'password')身份验证 Code: 'authorization_code' 授权需要 OIDC 客户端身份验证,以及至少 'code' 和 'redirect_uri' 参数,它们必须在令牌请求时传递给 OidcClient。 Exchange: 'urn:ietf:params:oauth:grant-type:token-exchange' 授权需要 OIDC 客户端身份验证,以及至少 'subject_token' 参数,该参数必须在令牌请求时传递给 OidcClient。 JWT: 'urn:ietf:params:oauth:grant-type:jwt-bearer' 授权需要 OIDC 客户端身份验证,以及至少一个 'assertion' 参数,该参数必须在令牌请求时传递给 OidcClient。
refresh: 'refresh_token' 授权需要 OIDC 客户端身份验证和刷新令牌。请注意,如果访问令牌获取响应包含刷新令牌,OidcClient 默认支持此授权。然而,在某些情况下,会提供带外的刷新令牌,例如,它可以在多个机密客户端的服务之间共享,等等。如果 'quarkus.oidc-client.grant-type' 设置为 'refresh',则 ciba: 'urn:openid:params:grant-type:ciba' 授权需要 OIDC 客户端身份验证,以及 'auth_req_id' 参数,该参数必须在令牌请求时传递给 OidcClient。 device: 'urn:ietf:params:oauth:grant-type:device_code' 授权需要 OIDC 客户端身份验证,以及 'device_code' 参数,该参数必须在令牌请求时传递给 OidcClient。 | client |
|
令牌授权响应中的访问令牌属性名称
环境变量: | string |
|
|
在令牌授权响应中刷新令牌属性名称
环境变量: | string |
|
|
令牌授权响应中的访问令牌到期属性名称
环境变量: | string |
|
|
在令牌授权响应中刷新令牌到期属性名称
环境变量: | string |
|
|
授权选项
环境变量: | Map<String,Map<String,String>> | |
|
要求所有使用"OidcClient"的过滤器在后结构初始化时获取令牌,在使用这些令牌之前可能会比较长。如果访问令牌在第一次使用并且没有刷新令牌可用之前过期,则应禁用此属性。
环境变量: | 布尔值 |
|
|
必须发送到令牌端点的自定义 HTTP 标头
环境变量: | Map<String,String> |
要写入持续时间值,请使用标准 java.time.Duration 格式。如需更多信息,请参阅 Duration#parse ()Java API 文档。
您还可以使用简化的格式,从数字开始:
- 如果值只是一个数字,它代表时间(以秒为单位)。
-
如果值为数字,后跟
ms,代表时间(毫秒)。
在其他情况下,简化的格式被转换为 java.time.Duration 格式以进行解析:
-
如果该值是一个数字,后跟
h、m或s,则前缀为PT。 -
如果值为数字,后跟
d,则会以P为前缀。
1.5.2. OIDC 令牌传播 复制链接链接已复制到粘贴板!
build 时修复的 - 配置属性在构建时修复 - 所有其他配置属性在运行时可覆盖
| 配置属性 | 类型 | default |
|
在构建时为 如果启用了 OIDC Token Reactive Propagation。
环境变量: | 布尔值 |
|
|
在构建时被修复
在
例如,您可能需要使用 请注意,这个功能依赖于重复的上下文。有关 Vert.x 重复上下文的更多信息,请参阅本指南。
环境变量: | 布尔值 |
|
|
在构建时被修复 使用 "urn:ietf:params:oauth:grant-type:token-exchange" 或 "urn:ietf:params:oauth:grant-type:jwt-bearer" 令牌授权来交换新令牌的当前令牌。
环境变量: | 布尔值 |
|
|
在构建时为
配置的 OidcClient 的名称。请注意,只有在启用
环境变量: | string |
1.6. 参考 复制链接链接已复制到粘贴板!
第 2 章 OpenID Connect 客户端和令牌传播快速入门 复制链接链接已复制到粘贴板!
了解如何使用 OpenID Connect (OIDC)和带有过滤器的 OAuth2 客户端在应用程序中获取、刷新和传播访问令牌。
有关 Quarkus 中 OIDC 客户端和 令牌传播支持的更多信息,请参阅 OpenID Connect (OIDC)和 OAuth2 客户端和过滤器参考指南。
要使用 Bearer Token Authorization 保护应用程序,请参阅 OpenID Connect (OIDC) Bearer 令牌身份验证 指南。
2.1. 先决条件 复制链接链接已复制到粘贴板!
要完成本指南,您需要:
- 大约 15 分钟
- IDE
-
正确配置了
JAVA_HOME的 JDK 17+ - Apache Maven 3.8.6 或更高版本
- 正常工作的容器运行时(Docker 或 Podman)
- 如果要使用 Quarkus CLI,可选
- 如果要构建原生可执行文件(或者使用原生容器构建,则可选的 Mandrel 或 GraalVM) https://quarkus.io/version/3.15/guides/building-native-image#configuring-graalvm
- jq 工具
2.2. 架构 复制链接链接已复制到粘贴板!
在本例中,应用程序使用两个 Jakarta REST 资源构建,即 FrontendResource 和 ProtectedResource。在这里,Frontend Resource 使用三种方法之一将访问令牌传播到 ProtectedResource :
- 它可以通过在传播令牌前使用 OIDC 客户端过滤器来获取令牌。
-
它可以使用编程创建的 OIDC 客户端来获取令牌,并通过将其作为 HTTP 授权标头值传递给 REST 客户端方法来传播令牌。
- 它可以使用 OIDC 令牌传播过滤器来传播传入的访问令牌。
FrontendResource 有八个端点:
-
/frontend/user-name-with-oidc-client-token -
/frontend/admin-name-with-oidc-client-token -
/frontend/user-name-with-oidc-client-token-header-param -
/frontend/admin-name-with-oidc-client-token-header-param -
/frontend/user-name-with-oidc-client-token-header-param-blocking -
/frontend/admin-name-with-oidc-client-token-header-param-blocking -
/frontend/user-name-with-propagated-token -
/frontend/admin-name-with-propagated-token
当 /frontend/user-name-with-oidc-client-token 或 /frontend/admin-name-with-oidc-client-token 端点被调用时,Frontend Resource 使用带有 OIDC 客户端过滤器的 REST 客户端来获取和传播访问令牌到 ProtectedResource。当 /frontend/user-name-with-oidc-client-token-header-param 或 /frontend/admin-name-with-oidc-client-token-header-param 端点被调用,Frontend Resource 使用以编程方式创建的 OIDC 客户端来获取和传播访问令牌到 ProtectedResource,方法是将其作为 HTTP Authorization 标头值传递给 REST 客户端方法。当 /frontend/user-name-with-propagated-token 或 /frontend/admin-name-with-propagated-token 端点被调用时,FrontendResource 使用带有 OIDC Token Propagation Filter 的 REST 客户端将当前的传入访问令牌传播到 ProtectedResource。
ProtectedResource 有两个端点:
-
/protected/user-name -
/protected/admin-name
两个端点返回从传入访问令牌中提取的用户名,该令牌从 FrontendResource 传播到 ProtectedResource。这些端点之间的唯一区别在于,只有在当前访问令牌具有用户角色时才允许调用 /protected/ ,只有在当前访问令牌具有 user -nameadmin 角色时才允许调用 /protected/admin-name。
2.3. 解决方案 复制链接链接已复制到粘贴板!
我们建议您按照下一小节中的说明进行操作,并逐步创建应用程序步骤。但是,您可以进入已完成的示例。
克隆 Git 存储库: git clone https://github.com/quarkusio/quarkus-quickstarts.git -b 3.15,或下载 存档。
解决方案位于 security-openid-connect-client-quickstart 目录中。
2.4. 创建 Maven 项目 复制链接链接已复制到粘贴板!
首先,您需要一个新项目。使用以下命令创建新项目:
使用 Quarkus CLI:
quarkus create app org.acme:security-openid-connect-client-quickstart \ --extension='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest' \ --no-code cd security-openid-connect-client-quickstartquarkus create app org.acme:security-openid-connect-client-quickstart \ --extension='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest' \ --no-code cd security-openid-connect-client-quickstartCopy to Clipboard Copied! Toggle word wrap Toggle overflow 要创建 Gradle 项目,请添加--
gradle or--gradle-kotlin-dsl选项。有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。
使用 Maven:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 要创建 Gradle 项目,请添加
-DbuildTool=gradleor-DbuildTool=gradle-kotlin-dsl选项。
对于 Windows 用户:
-
如果使用 cmd,(不要使用反向斜杠
\并将所有内容放在同一行中) -
如果使用 Powershell,则双引号中的 wrap
-D参数,如"-DprojectArtifactId=security-openid-connect-client-quickstart"
它生成 Maven 项目,导入 oidc、rest-client-oidc-filter、rest-client-oidc-token-propagation,以及 其余 扩展。
如果您已经配置了 Quarkus 项目,您可以在项目基本目录中运行以下命令来将这些扩展添加到项目中:
使用 Quarkus CLI:
quarkus extension add oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest
quarkus extension add oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,restCopy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Maven:
./mvnw quarkus:add-extension -Dextensions='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest'
./mvnw quarkus:add-extension -Dextensions='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest'Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Gradle:
./gradlew addExtension --extensions='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest'
./gradlew addExtension --extensions='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest'Copy to Clipboard Copied! Toggle word wrap Toggle overflow
它为构建文件添加以下扩展:
使用 Maven:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Gradle:
implementation("io.quarkus:quarkus-oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest")implementation("io.quarkus:quarkus-oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest")Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.5. 编写应用程序 复制链接链接已复制到粘贴板!
首先实施 ProtectedResource :
ProtectedResource 返回一个来自 userName () 和 adminName () 方法的名称。名称从当前的 JsonWebToken 中提取。
接下来,添加以下 REST 客户端:
-
RestClientWithOidcClientFilter,它使用quarkus-rest-client-oidc-filter扩展提供的 OIDC 客户端过滤器来获取和传播访问令牌。 -
RestClientWithTokenHeaderParam,它接受以编程方式创建的 OidcClient 作为 HTTPAuthorization标头值而获取的令牌。 -
RestClientWithTokenPropagationFilter,它使用quarkus-rest-client-oidc-token-propagation扩展提供的 OIDC 令牌传播过滤器来获取和传播访问令牌。
添加 RestClientWithOidcClientFilter REST 客户端:
- 1
- 在 REST 客户端中注册 OIDC 客户端过滤器,以获取和传播令牌。
添加 RestClientWithTokenHeaderParam REST 客户端:
添加 RestClientWithTokenPropagationFilter REST 客户端:
- 1
- 使用 REST 客户端注册 OIDC 令牌传播过滤器,以传播传入的已存在的令牌。
不要在同一 REST 客户端中使用 RestClientWithOidcClientFilter 和 RestClientWithTokenPropagationFilter 接口,因为它们可能会发生冲突,从而导致问题。例如,OIDC 客户端过滤器可以从 OIDC 令牌传播过滤器覆盖令牌,或者传播过滤器在 none 可用时尝试传播令牌,则希望 OIDC 客户端过滤器获取新令牌。
另外,添加 OidcClientCreator 以编程方式创建 OIDC 客户端。OidcClientCreator 支持 RestClientWithTokenHeaderParam REST 客户端调用:
- 1
OidcClients可用于检索已初始化的、名为 OIDC 客户端并按需创建新的 OIDC 客户端。
现在,通过添加 FrontendResource 来完成创建应用程序:
- 1 5 6
FrontendResource使用带有 OIDC 客户端过滤器注入的RestClientWithOidcClientFilterREST 客户端来获取并传播访问令牌到ProtectedResource(当/frontend/user-name-with-oidc-client-token或/frontend/admin-name-with-oidc-client-token)。- 2 7 8
FrontendResource使用注入的RestClientWithTokenPropagationFilterREST 客户端以及 OIDC 令牌传播过滤器,以便在/frontend/user-name-with-propagated-token或/frontend/admin-name-with-propagated-token被调用时将当前的传入访问令牌传播到ProtectedResource。- 4 9 10
FrontendResource使用以编程方式创建的 OIDC 客户端来获取和传播访问令牌到ProtectedResource,方法是将其直接传递给注入的RestClientWithTokenHeaderParamREST 客户端方法作为 HTTPAuthorization标头值,即/frontend/user-name-with-oidc-client-token-header-param或/frontend/admin-name-with-oidc-client-token-header-param。- 11 12
- 有时,在向令牌传播令牌之前,可能需要以阻止方式获取令牌。本例演示了如何在这样的情形中获取令牌。
- 3
- 当 OIDC 客户端直接使用时,
io.quarkus.oidc.client.runtime.TokensHelper是一个非常有用的工具,没有 OIDC 客户端过滤器。要使用TokensHelper,请将 OIDC Client 传递给它以获取令牌,并且TokensHelper获取令牌,并在需要时以线程安全的方式刷新它们。
最后,添加 Jakarta REST ExceptionMapper :
此例外映射程序仅用于在测试期间验证 ProtectedResource 是否在令牌没有预期的角色时返回 403。如果没有此映射程序,Quarkus REST (以前称为 RESTEasy Reactive)可以正确地将来自 REST 客户端调用的异常转换为 500,以避免泄漏下游资源(如 ProtectedResource )的信息。但是,在测试中,无法断言 500 是由授权异常导致的,而不是一些内部错误。
2.6. 配置应用程序 复制链接链接已复制到粘贴板!
准备代码,您可以配置应用程序:
上述配置引用 Keycloak,由 ProtectedResource 用于验证传入的访问令牌,并且 OidcClient 使用 OidcClient 使用密码 授权来获取用户 alice 的令牌。两个 REST 客户端都指向 ProtectedResource 的 HTTP 地址。
将 %prod. 配置集前缀添加到 quarkus.oidc.auth-server-url 可确保当应用程序以 dev 或 test 模式运行时,为您启动 Dev Services。有关更多信息,请参阅 以 dev 模式运行应用。
2.7. 启动并配置 Keycloak 服务器 复制链接链接已复制到粘贴板!
当您以 dev 或 test 模式运行应用程序时,不要启动 Keycloak 服务器 ; Keycloak 的 Dev Services 启动容器。有关更多信息,请参阅 以 dev 模式运行应用。确保将 realm 配置文件放在 classpath 上,它位于 target/classes 目录中。此放置可确保文件在 dev 模式中自动导入。但是,如果您已构建了一个 完整的解决方案,则不需要将 realm 文件添加到类路径,因为构建过程已完成。
要启动 Keycloak 服务器,您可以使用 Docker 并运行以下命令:
docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
将 {keycloak.version} 设置为 25.0.6 或更高版本。
您可以在 localhost:8180 访问您的 Keycloak 服务器。
以 admin 用户身份登录,以访问 Keycloak 管理控制台。密码是 admin。
导入 realm 配置文件以创建 新域。如需了解更多详细信息,请参阅关于如何创建新域的 Keycloak 文档。https://www.keycloak.org/docs/latest/server_admin/index.html#_create-realm
此 quarkus 域文件添加 frontend 客户端,以及 alice 和 admin 用户。alice 具有 用户角色。admin 同时具有 user 和 admin 角色。
2.8. 以 dev 模式运行应用程序 复制链接链接已复制到粘贴板!
要在 dev 模式下运行应用程序,请使用:
使用 Quarkus CLI:
quarkus dev
quarkus devCopy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Maven:
./mvnw quarkus:dev
./mvnw quarkus:devCopy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Gradle:
./gradlew --console=plain quarkusDev
./gradlew --console=plain quarkusDevCopy to Clipboard Copied! Toggle word wrap Toggle overflow
Keycloak 的 dev Services 启动 Keycloak 容器,并导入 quarkus-realm.json。
打开位于 /q/dev-ui 的 Dev UI,然后点击 OpenID Connect Dev UI 卡中的 Keycloak 供应商 链接。
提示时,登录到 OpenID Connect Dev UI 提供的 单个页面应用程序 :
以
alice身份登录,密码为alice。此用户同时具有admin和 用户角色。-
访问
/frontend/user-name-with-propagated-token,它返回200。 -
访问
/frontend/admin-name-with-propagated-token,它返回200。
-
访问
注销,然后以
bob用户身份使用密码bob重新登录。此用户具有用户角色。-
访问
/frontend/user-name-with-propagated-token,它返回200。 -
访问
/frontend/admin-name-with-propagated-token,它返回403。
-
访问
您已测试了 FrontendResource 可以从 OpenID Connect Dev UI 传播访问令牌。
2.9. 在 JVM 模式下运行应用程序 复制链接链接已复制到粘贴板!
在以 dev 模式探索应用后,您可以将其作为标准 Java 应用运行。
首先,编译它:
使用 Quarkus CLI:
quarkus build
quarkus buildCopy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Maven:
./mvnw install
./mvnw installCopy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Gradle:
./gradlew build
./gradlew buildCopy to Clipboard Copied! Toggle word wrap Toggle overflow
然后运行它:
java -jar target/quarkus-app/quarkus-run.jar
java -jar target/quarkus-app/quarkus-run.jar
2.10. 以原生模式运行应用程序 复制链接链接已复制到粘贴板!
您可以将此演示编译为原生代码,不需要修改。
这意味着,您不再需要在生产环境中安装 JVM,因为运行时技术包含在生成的二进制中,并优化以最小资源运行。
编译需要更长的时间,因此默认关闭此步骤。要再次构建,请启用 原生 配置集:
使用 Quarkus CLI:
quarkus build --native
quarkus build --nativeCopy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Maven:
./mvnw install -Dnative
./mvnw install -DnativeCopy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 Gradle:
./gradlew build -Dquarkus.native.enabled=true
./gradlew build -Dquarkus.native.enabled=trueCopy to Clipboard Copied! Toggle word wrap Toggle overflow
在稍等片刻后,构建完成后,您可以直接运行原生二进制文件:
./target/security-openid-connect-quickstart-1.0.0-SNAPSHOT-runner
./target/security-openid-connect-quickstart-1.0.0-SNAPSHOT-runner
2.11. 测试应用程序 复制链接链接已复制到粘贴板!
有关以 dev 模式测试应用程序的更多信息,请参阅前面 在 dev mode 中运行该应用。
您可以使用 curl 来测试以 JVM 或原生模式启动的应用程序。
获取 alice 的访问令牌:
使用此令牌调用 /frontend/user-name-with-propagated-token。此命令返回 200 状态代码和名称 alice :
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-propagated-token \ -H "Authorization: Bearer "$access_token
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-propagated-token \
-H "Authorization: Bearer "$access_token
使用相同的令牌调用 /frontend/admin-name-with-propagated-token。与前面的命令不同,这个命令会返回 403,因为 alice 只有一个 用户角色 :
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-propagated-token \ -H "Authorization: Bearer "$access_token
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-propagated-token \
-H "Authorization: Bearer "$access_token
接下来,获取 admin 的访问令牌:
使用此令牌调用 /frontend/user-name-with-propagated-token。此命令返回 200 状态代码和名称 admin :
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-propagated-token \ -H "Authorization: Bearer "$access_token
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-propagated-token \
-H "Authorization: Bearer "$access_token
使用相同的令牌调用 /frontend/admin-name-with-propagated-token。此命令还会返回 200 状态代码和名称 admin,因为 具有 admin user 和 admin 角色:
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-propagated-token \ -H "Authorization: Bearer "$access_token
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-propagated-token \
-H "Authorization: Bearer "$access_token
接下来,检查 FrontendResource 方法,它不会传播现有的令牌,而是使用 OidcClient 获取和传播令牌。如上所示,OidcClient 配置为获取 alice 用户的令牌。
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-oidc-client-token
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-oidc-client-token
此命令返回 200 状态代码和名称 alice。
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-oidc-client-token
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-oidc-client-token
与前面的命令不同,此命令会返回 403 状态代码。
接下来,测试以编程方式创建的 OIDC 客户端是否在 reactive 和 imperative (阻塞)模式中同时使用 RestClientWithTokenHeaderParam 正确获取并传播令牌。
调用 /user-name-with-oidc-client-token-header-param。此命令返回 200 状态代码和名称 alice :
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-oidc-client-token-header-param
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-oidc-client-token-header-param
调用 /admin-name-with-oidc-client-token-header-param。与前面的命令不同,这个命令会返回一个 403 状态代码:
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-oidc-client-token-header-param
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-oidc-client-token-header-param
接下来,在阻塞模式下测试使用 OIDC 客户端的端点。
调用 /user-name-with-oidc-client-token-header-param-blocking。此命令返回 200 状态代码和名称 alice :
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-oidc-client-token-header-param-blocking
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-oidc-client-token-header-param-blocking
调用 /admin-name-with-oidc-client-token-header-param-blocking。与前面的命令不同,这个命令会返回一个 403 状态代码:
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-oidc-client-token-header-param-blocking
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-oidc-client-token-header-param-blocking