Dev Services and Dev UI for OpenID Connect (OIDC)

您可以为 Keycloak 使用 Dev Services,为 OpenID Connect (OIDC) Keycloak 提供程序使用 Dev UI,并将这些服务调整为其他 OpenID Connect 提供程序。您还可以在运行 Quarkus 之前已启动的 OpenID Connect 提供程序中使用 Dev UI。

Introduction

Quarkus 提供 Keycloak 的 Dev Services 功能,该功能在 quarkus-oidc 扩展程序在开发模式下启动时默认启用,集成测试在测试模式下运行,并且没有配置 quarkus.oidc.auth-server-url 属性时。Keycloak 的 Dev Services 功能为开发和测试模式启动一个 Keycloak 容器。它通过注册现有的 Keycloak 领域或创建新的领域来初始化它们,并为您提供您立即开始开发由 Keycloak 保护的 Quarkus 应用程序所需的客户端和用户。检测到 application.properties 或领域文件发生更改时,该容器将重新启动。

此外,Dev UI 可在 /q/dev 获得,通过开发人员 UI 页面补充此功能,可帮助从 Keycloak 获取令牌,并测试 Quarkus 应用程序。

如果已设置 quarkus.oidc.auth-server-url,则会激活通用 OpenID Connect Dev 控制台(所有 OpenID Connect 提供程序均可使用)。有关更多信息,请参阅 Dev UI for all OpenID Connect providers

Dev Services for Keycloak

application.properties 文件中不配置 quarkus.oidc 属性的情况下启动应用程序:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

控制台将显示类似于此的输出:

KeyCloak Dev Services Starting:
2021-11-02 17:14:24,864 INFO  [org.tes.con.wai.str.HttpWaitStrategy] (build-10) /unruffled_agnesi: Waiting for 60 seconds for URL: http://localhost:32781 (where port 32781 maps to container port 8080)
2021-11-02 17:14:44,170 INFO  [io.qua.oid.dep.dev.key.KeycloakDevServicesProcessor] (build-10) Dev Services for Keycloak started.

在登录到 Keycloak 管理控制台时,用户名为 admin,密码为 admin

请注意,如果 Dev Services for Keycloak 检测到标记为 quarkus-dev-service-keycloak 的现有容器,则其默认为不启动新的容器。它会连接到此容器,前提是 quarkus.keycloak.devservices.service-name 属性的值与标签的值匹配(默认为 quarkus)。在这种情况下,在运行以下命令时,预期输出会有轻微更改:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev
2021-08-27 18:42:43,530 INFO  [io.qua.dev.com.ContainerLocator] (build-15) Dev Services container found: 48fee151a31ddfe32c39965be8f61108587b25ed2f66cdc18bb926d9e2e570c5 (quay.io/keycloak/keycloak:21.0.2). Connecting to: 0.0.0.0:32797.
2021-08-27 18:42:43,600 INFO  [io.qua.oid.dep.dev.key.KeycloakDevServicesProcessor] (build-15) Dev Services for Keycloak started.
...

如果 Keycloak 容器在默认的 60 秒超时时间内没有准备就绪,则可以通过延长超时时间来解决此问题。例如,使用 quarkus.devservices.timeout=2M 将其设置为 2 分钟。

您可以通过指定 quarkus.keycloak.devservices.shared=false 来关闭容器的共享。

现在,打开主 Dev UI page 并观察链接到 Keycloak 页面的 OpenID Connect 卡片。例如:

dev ui oidc keycloak card

单击 Keycloak provider 链接。此操作将打开一个 Keycloak 页面,其外观会根据 Dev Services for Keycloak 功能的配置方式而有所不同。

Developing service applications

默认情况下,Keycloak 页面可用于支持 Quarkus OIDC service application 的开发。

Authorization code grant

如果你在 application.properties 文件中设置 quarkus.oidc.devui.grant.type=code (这是一个默认值),则使用 authorization_code 授权来获取访问令牌和 ID 令牌。建议使用此授权来模拟典型的流程,其中单页应用程序 (SPA) 获取令牌并使用它们来访问 Quarkus 服务。

首先,你会看到 Log into Single Page Application 的选项。例如:

dev ui keycloak sign in to spa

在身份验证过程中选择 Keycloak 领域和要使用的客户端 ID。

此 SPA 表示一个公共 OpenID Connect 客户端;因此,你输入的客户端 ID 必须标识没有密钥的公共 Keycloak 客户端。这是因为 SPA 不是 Web 应用程序,并且如果期望客户端密钥也完成授权代码流程,则无法安全处理完成授权代码流程所需的密钥。 如果已创建默认领域,或者配置了 quarkus.oidc.credentials.secret 并使用了单个自定义领域,则只能使用此 SPA 支持带有密钥的客户端。在这两种情况下,当 Keycloak 将用户重定向回 SPA 之后,SPA 可以找出完成授权代码流程可能需要的客户端密钥。

然后,在选择*Log into Single Page Application*,您将被重定向到 Keycloak 进行身份验证,例如,作为`alice:alice`然后,您将返回表示 SPA 的页面:

dev ui keycloak test service from spa

您可以查看获得的访问和 ID 令牌,例如:

dev ui keycloak decoded tokens

此视图显示左侧的编码 JSON Web 令牌 (JWT) 令牌,并使用红色突出显示标头、绿色突出显示有效负载或声明,并使用蓝色突出显示签名。它还显示右侧的解码 JWT 令牌,您可以在其中看到标头、声明名称及其值。

然后,通过输入相对服务路径并发送令牌来测试服务。SPA 通常将访问令牌发送到应用程序端点,因此请选择*With Access Token*选项,例如:

dev ui keycloak test access token

要清除测试结果区,请使用右下角的橡皮擦图标。

有时,ID 令牌作为持有者令牌转发到应用程序前端。这有助于端点识别登录到 SPA 的用户或执行带外令牌验证。在这种情况下,选择*With ID Token*选项。

手动输入服务路径并不理想。有关启用 Swagger 或 GraphQL UI 以使用 OIDC Dev UI 已经获取的访问令牌测试服务的信息,请参阅Test with Swagger UI or GraphQL UI部分。

最后,您可以单击*Log Out*image::dev-ui-keycloak-logout.png[alt=Dev UI Keycloak - Log Out,role="center"],以便您可以身份验证到 Keycloak 作为不同的用户。

当您尝试*Log into Single Page Application*时,Keycloak 可能会返回错误。例如,`quarkus.oidc.client-id`可能与导入到 Keycloak 中的领域中的客户端 ID 不匹配,或者此领域中的客户端可能未正确配置以支持授权代码流。在这种情况下,Keycloak 会返回一个`error_description`查询参数,并且 Dev UI 也会显示此错误描述。例如:

dev ui keycloak login error

如果出现错误,请使用*Keycloak Admin*选项登录到 Keycloak,根据需要更新领域配置,并检查`application.properties`。

Test with Swagger UI or GraphQL UI

如果您项目中使用了`quarkus-smallrye-openapi`或`quarkus-smallrye-graphql`,则您可以避免手动输入服务路径并使用 Swagger UI 或 GraphQL UI 测试您的服务。例如,在开发模式下使用`quarkus-smallrye-openapi`和`quarkus-smallrye-graphql`依赖项启动 Quarkus。登录到 Keycloak 后,您会看到以下选项:

dev ui keycloak test service swaggerui graphql

例如,单击*Swagger UI*将在新浏览器选项卡中打开 Swagger UI,您可以在其中使用 Dev UI 为 Keycloak 获取的令牌来测试服务。Swagger UI 不会尝试再次重新身份验证。在 Swagger UI 中,不要选择 Swagger UI `Authorize`选项;OIDC Dev UI 已为 Swagger UI 授权并提供访问令牌以供其用于测试。

与 GraphQL UI 的集成工作方式类似;使用 Dev UI 为 Keycloak 获取的访问令牌。

您可能需要为 Dev UI 为 Keycloak 发起的授权代码流注册重定向 URI。这是因为 Keycloak 可能会强制要求已验证的用户仅重定向到已配置的重定向 URI。建议在生成环境中执行此操作,以避免用户被重定向到错误的端点,如果身份验证请求 URI 中正确的`redirect_uri`参数已被操纵,则可能会发生这种情况。 如果 Keycloak 强制执行它,您会看到一个身份验证错误,告知您`redirect_uri`值错误。 在这种情况下,选择右上角的*Keycloak Admin*选项,登录为`admin:admin`,选择测试领域和 Dev UI 为 Keycloak 配置的客户端,并将`http://localhost:8080/q/dev-ui/io.quarkus.quarkus-oidc/keycloak-provider`添加到`Valid Redirect URIs`。如果您在启动 Quarkus 时使用了`-Dquarkus.http.port`,则将`8080`更改为`quarkus.http.port`的值 如果容器在运行在不同端口上的多个应用程序之间共享,则必须为每个应用程序注册`redirect_uri`值。 您可以将`redirect_uri`值设置为`,仅用于测试目的,尤其是在容器在多个应用程序之间共享时。 如果没有导入自定义领域,当 Dev Services 为 Keycloak 创建默认领域时,将`redirect_uri`值设置为`。

Implicit grant

如果您在 application.properties 文件中设置了 quarkus.oidc.devui.grant.type=implicit,则使用 implicit 授权来获取访问令牌和 ID 令牌。仅当授权代码授权无法运行时,才使用此授权模拟单页应用程序;例如,当客户端已在 Keycloak 中配置为支持隐式授权时。

Password grant

如果您在 application.properties 文件中设置了 quarkus.oidc.devui.grant.type=password,则会看到类似于以下内容的屏幕:

dev ui keycloak password grant

选择领域,输入客户端 ID 和机密、用户名和密码、相对服务端点路径,然后单击 Test service。它会返回一个状态代码,如 200403401404。如果用户名也已在包含用户名和密码的 quarkus.keycloak.devservices.users 映射属性中设置,则在测试服务时不必设置密码。请注意,您不必初始化 quarkus.keycloak.devservices.users 来使用 password 授权测试服务。

在 Dev UI 控制台中,您还可以看到类似于以下内容的输出:

2021-07-19 17:58:11,407 INFO  [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Using password grant to get a token from 'http://localhost:32818/realms/quarkus/protocol/openid-connect/token' for user 'alice' in realm 'quarkus' with client id 'quarkus-app'
2021-07-19 17:58:11,533 INFO  [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Test token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6Z2tDazJQZ1JaYnVlVG5kcTFKSW1sVnNoZ2hhbWhtbnBNcXU0QUt5MnJBIn0.ey...
2021-07-19 17:58:11,536 INFO  [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Sending token to 'http://localhost:8080/api/admin'
2021-07-19 17:58:11,674 INFO  [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Result: 200

通过使用 password 授权从 Keycloak 获取令牌,并将其发送到服务端点。

Client credentials grant

如果您设置了 quarkus.oidc.devui.grant.type=client,则会使用 client_credentials 授权获取令牌,在此情况下,页面中不会显示 User 字段:

dev ui keycloak client credentials grant

选择领域,输入客户端 ID 和机密、相对服务端点路径,然后单击 Test service。它会返回一个状态代码,如 200403401404

Developing OpenID Connect web-app applications

要开发 Quarkus OIDC web application,请在启动应用程序之前,在 application.properties 文件中设置 quarkus.oidc.application-type=web-app

启动应用程序会显示一个类似于以下内容的屏幕:

dev ui keycloak sign in to service

设置一个相对服务端点路径并单击 Log in to your web application。您会在新的浏览器标签中重定向到 Keycloak,以输入用户名和密码,然后才能从 Quarkus 应用程序获取响应。

在此情况下,Dev UI 并不是非常有用,因为 Quarkus OIDC web-app 应用程序控制授权代码流并获取令牌。

为了让 Dev UI 更有助于支持 OIDC web-app 应用程序的开发,请考虑为 quarkus.oidc.application-type 设置特定于配置文件的值:

%prod.quarkus.oidc.application-type=web-app
%test.quarkus.oidc.application-type=web-app
%dev.quarkus.oidc.application-type=service

此配置文件可确保在您的 web-app 应用程序在开发模式下运行时,所有在 Developing service applications 中描述的 Dev UI 选项都可用。此方法的局限性在于,使用代码流返回并通过 Dev UI 获取的访问令牌和 ID 令牌作为 HTTP Bearer 令牌发送到端点,如果您的端点需要注入 IdToken,则不起作用。但是,如果您的 web-app 应用程序仅使用访问令牌(例如,作为角色的来源或获取 UserInfo),则它会按预期工作,即使它在开发模式下被视为 service 应用程序也是如此。

对于开发模式,一个更好的选择是将 application-type 属性设为 hybrid

%prod.quarkus.oidc.application-type=web-app
%test.quarkus.oidc.application-type=web-app
%dev.quarkus.oidc.application-type=hybrid

此类型可确保如果在没有 OIDC Dev UI 的情况下从浏览器访问应用程序(在开发模式下),则 Quarkus OIDC 也会执行授权代码流,就像在生产模式下一样。OIDC Dev UI 也会更有益,因为混合应用程序也可以接受出示者访问令牌。

Running the tests

可以在 Continuous Testing 模式中针对在测试模式下启动的 Keycloak 容器运行测试。

还建议使用 Dev Services for Keycloak 来针对 Keycloak 运行集成测试。有关更多信息,请参阅 Testing OpenID Connect Service Applications with Dev ServicesTesting OpenID Connect WebApp Applications with Dev Services

Keycloak initialization

包含由 Quarkus 提供支持的 Keycloak 分发的 quay.io/keycloak/keycloak:25.0.2 映像用于默认启动容器。quarkus.keycloak.devservices.image-name 可用于更改 Keycloak 映像名称。例如,将其设为 quay.io/keycloak/keycloak:19.0.3-legacy,以使用由 WildFly 提供支持的 Keycloak 分发。请注意,基于 Quarkus 的 Keycloak 分发仅在 Keycloak 20.0.0 中才可用。

Keycloak 的开发服务接下来会初始化一个已启动的 Keycloak 服务器。

默认情况下,会创建配有 quarkusquarkus-app 客户端、secret 密码、alicebob 用户(密码与名称匹配)以及 useradmin 角色,其中 alice 获赋予 adminuser 角色,而 bob 获赋予 user 角色。

用户名、密码和角色可以通过 quarkus.keycloak.devservices.users (包含用户名和密码的映射)和 quarkus.keycloak.devservices.roles (包含用户名和逗号分隔的角色值)进行自定义。

例如:

%dev.quarkus.keycloak.devservices.users.duke=dukePassword
%dev.quarkus.keycloak.devservices.roles.duke=reader
%dev.quarkus.keycloak.devservices.users.john=johnPassword
%dev.quarkus.keycloak.devservices.roles.john=reader,writer

此配置会创建两个用户:* duke 配有 dukePassword 密码和 reader 角色* john 配有 johnPassword 密码和 readerwriter 角色

若要自定义客户端 ID 和密码,可以使用 quarkus.oidc.client-idquarkus.oidc.credentials.secret 属性。

但您的 Keycloak 配置可能比较复杂,需要设置更多属性。

这就是为什么在使用默认或已配置的领域、客户端、用户和角色属性初始化 Keycloak 之前始终会检查 quarkus.keycloak.devservices.realm-path。如果领域文件存在于文件系统或类路径,则仅使用此领域初始化 Keycloak,例如:

quarkus.keycloak.devservices.realm-path=quarkus-realm.json

您可以使用 quarkus.keycloak.devservices.realm-path 通过提供逗号分隔的文件列表来使用多个领域文件初始化 Keycloak:

quarkus.keycloak.devservices.realm-path=quarkus-realm1.json,quarkus-realm2.json

此外,Keycloak 页面提供了一个使用右上角的 Keycloak Admin 选项进行 Sign In To Keycloak To Configure Realms 的选项:

dev ui keycloak admin

admin:admin 登录 Keycloak 以进一步自定义领域属性,创建或导入新的领域,或导出领域。

您还可以将类路径和文件系统资源复制到容器中。例如,如果您的应用程序使用已部署到 Keycloak 的 jar 文件中配置 Keycloak 授权,那么您可以配置 Dev Services for Keycloak 来将此 jar 复制到 Keycloak 容器,如下所示:

quarkus.keycloak.devservices.resource-aliases.policies=/policies.jar 1
quarkus.keycloak.devservices.resource-mappings.policies=/opt/keycloak/providers/policies.jar 2
1 已为类路径 /policies.jar 资源创建了 policies 别名。

策略 jar 也可位于文件系统中。<2> 策略 jar 被映射到 /opt/keycloak/providers/policies.jar 容器位置。

Disable Dev Services for Keycloak

以下情况均为不激活 Keycloak 开发服务: 如果 quarkus.oidc.auth-server-url 已初始化,或无论是否使用 Keycloak,已使用 quarkus.oidc.tenant.enabled=false 禁用了默认 OIDC 租户。

如果您不想启动 Keycloak 开发服务容器或不使用 Keycloak,也可以使用 quarkus.keycloak.devservices.enabled=false 禁用此功能——只有在您期望在没有 quarkus.oidc.auth-server-url 的情况下启动 quarkus:dev 时才需要执行此操作。

当 Keycloak 开发服务被禁用且 quarkus.oidc.auth-server-url 属性尚未初始化时,主开发 UI 页面会包含一个空的 OpenID Connect 卡牌:

dev ui oidc card

如果已设置 quarkus.oidc.auth-server-url,则能够激活通用 OpenID Connect 开发控制台,可与所有 OpenID Connect 提供程序一同使用。有关更多信息,请参阅 Dev UI for all OpenID Connect providers 部分。

Dev UI for all OpenID Connect providers

在满足以下条件的情况下,将激活所有 OpenID Connect 提供程序的开发 UI:

  • quarkus.oidc.auth-server-url 指向已启动的 OpenID Connect 提供程序,可以是 Keycloak 或其他提供程序。

  • quarkus.oidc.application-type 设置为 service,这是默认值,或者 hybrid

  • The quarkus.oidc.client-id is set.

设置 quarkus.oidc.credentials.secret,很可能 Keycloak 和其他提供者需要授权代码流,这是从 Dev UI 初始化的,以便完成,除非使用 quarkus.oidc.client-id 标识的客户端在 OpenID Connect 提供者的管理台中配置为公共客户端。

例如,你可以使用 Dev UI 测试带有此配置的 Google 认证:

quarkus.oidc.provider=google
quarkus.oidc.application-type=hybrid
quarkus.oidc.client-id=${google-client-id}
quarkus.oidc.credentials.secret=${google-client-secret}

运行:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

此命令输出一条消息,与以下示例类似:

...
2021-09-07 15:53:42,697 INFO  [io.qua.oid.dep.dev.OidcDevConsoleProcessor] (build-41) OIDC Dev Console: discovering the provider metadata at https://accounts.google.com/.well-known/openid-configuration
...

如果提供者的元数据发现已成功,那么在你打开 Dev UI page 主页后,你可以看到以下 OpenID Connect 卡片,引用 Google 提供者:

dev ui oidc devconsole card

遵循链接登录到你的提供者,获取令牌并测试应用程序。体验与 Authorization code grant for Keycloak 部分中描述的相同,其中 Keycloak 容器的 Dev 服务已经启动,特别是如果你使用 Keycloak。

你可能需要配置你的 OpenID Connect 提供者,以支持重定向回 Dev Console。你添加 http://localhost:8080/q/dev-ui/io.quarkus.quarkus-oidc/<providerName>-provider 作为受支持的重定向和注销 URL 之一,其中 <providerName> 必须替换为 Dev UI 中显示的提供者名称,例如,<providerName>

如果你使用其他提供者,那么 Authorization code grant for Keycloak 部分中描述的 Dev UI 体验可能略有不同。例如,访问令牌可能不是 JWT 格式,因此无法显示其内部内容。但是,所有提供者都应该以 JWT 格式返回 ID 令牌。

当前访问令牌默认用于通过 Swagger UI 或 GrapghQL UI 测试服务。如果提供者(除了 Keycloak)返回二进制访问令牌,那么它仅在该提供者具有令牌内省端点时才与 Swagger UI 或 GrapghQL UI 一起使用;否则,始终采用 JWT 格式的 IdToken 传递给 Swagger UI 或 GrapghQL UI。在这种情况下,你可以通过手动 Dev UI 测试,验证始终为当前二进制访问令牌返回 401。此外,请注意,使用 IdToken 作为这两个用户界面中的任何一个的备用方法,仅适用于授权代码流。

一些提供者,例如 Auth0,不支持标准 RP 初始化注销,因此必须配置特定提供者的注销属性,以便注销选项可见。有关更多信息,请参阅《OpenID Connect 授权代码流机制以保护 Web 应用程序》指南中的 User-initiated logout 部分。

类似地,如果你希望使用 passwordclient_credentials 授权 Dev UI 获取令牌,那么你可能需要配置一些额外的特定提供者属性,例如:

quarkus.oidc.devui.grant.type=password
quarkus.oidc.devui.grant-options.password.audience=http://localhost:8080

Non-application root path considerations

本文档在多个位置引用 http://localhost:8080/q/dev-ui Dev UI URL,其中 q 是一个默认的非应用程序根路径。如果你自定义 quarkus.http.root-pathquarkus.http.non-application-root-path 属性,那么请相应地替换 q。有关更多信息,请参阅 Path resolution in Quarkus 博文。