使用 OpenID Connect (OIDC) Bearer 令牌身份验证保护服务应用程序
使用 Quarkus OpenID Connect (OIDC) 扩展程序,通过 Bearer 令牌认证来保护 Jakarta REST 应用程序。Bearer 令牌由符合 OIDC 和 OAuth 2.0 的授权服务器颁发,例如 Keycloak。
有关 OIDC Bearer 令牌认证的更多信息,请参阅 Quarkus OpenID Connect (OIDC) Bearer 令牌认证指南。
如果要通过使用 OIDC 授权代码流认证来保护 Web 应用程序,请参阅用于保护 Web 应用程序的 OpenID Connect 授权代码流机制指南。
先决条件
要完成本指南,您需要
-
大约 15 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
一个正常工作的容器运行时(Docker 或 Podman)
-
如果您想使用它,可以选择 Quarkus CLI
-
如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置
架构
此示例演示了如何构建一个提供两个端点的简单微服务
-
/api/users/me
-
/api/admin
这些端点受到保护,只有当客户端发送一个 Bearer 令牌以及请求时才能访问,该令牌必须有效(例如,签名、过期时间和受众)并且受到微服务的信任。
Keycloak 服务器颁发 Bearer 令牌,并表示令牌颁发的主题。因为它是一个 OAuth 2.0 授权服务器,所以该令牌还引用了代表用户行事的客户端。
任何具有有效令牌的用户都可以访问 /api/users/me
端点。作为响应,它会返回一个 JSON 文档,其中包含从令牌信息中获取的用户详细信息。
/api/admin
端点受 RBAC(基于角色的访问控制)保护,只有具有 admin
角色的用户才能访问。在此端点,@RolesAllowed
注释用于声明性地强制执行访问约束。
解决方案
按照以下部分的说明,逐步创建应用程序。您也可以直接转到已完成的示例。
您可以通过运行命令 git clone https://github.com/quarkusio/quarkus-quickstarts.git
来克隆 Git 存储库,也可以下载一个 存档。
该解决方案位于 security-openid-connect-quickstart
目录中。
创建 Maven 项目
您可以创建一个带有 oidc
扩展程序的新 Maven 项目,也可以将扩展程序添加到现有的 Maven 项目。完成以下命令之一
要创建一个新的 Maven 项目,请使用以下命令
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数包装在双引号中,例如"-DprojectArtifactId=security-openid-connect-quickstart"
如果您已经配置了 Quarkus 项目,则可以通过在项目根目录中运行以下命令将 oidc
扩展程序添加到您的项目中
quarkus extension add oidc
./mvnw quarkus:add-extension -Dextensions='oidc'
./gradlew addExtension --extensions='oidc'
这会将以下内容添加到您的构建文件中
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>
implementation("io.quarkus:quarkus-oidc")
编写应用程序
-
按以下示例所示实现
/api/users/me
端点,这是一个常规的 Jakarta REST 资源package org.acme.security.openid.connect; import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import org.jboss.resteasy.reactive.NoCache; import io.quarkus.security.identity.SecurityIdentity; @Path("/api/users") public class UsersResource { @Inject SecurityIdentity securityIdentity; @GET @Path("/me") @RolesAllowed("user") @NoCache public User me() { return new User(securityIdentity); } public static class User { private final String userName; User(SecurityIdentity securityIdentity) { this.userName = securityIdentity.getPrincipal().getName(); } public String getUserName() { return userName; } } }
-
按以下示例所示实现
/api/admin
端点package org.acme.security.openid.connect; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; @Path("/api/admin") public class AdminResource { @GET @RolesAllowed("admin") @Produces(MediaType.TEXT_PLAIN) public String admin() { return "granted"; } }
此示例的主要区别在于,
@RolesAllowed
注释用于验证只有被授予admin
角色的用户才能访问该端点。
SecurityIdentity
的注入在 @RequestScoped
和 @ApplicationScoped
上下文中均受支持。
配置应用程序
-
通过在
src/main/resources/application.properties
文件中设置以下配置属性来配置 Quarkus OpenID Connect (OIDC) 扩展程序。%prod.quarkus.oidc.auth-server-url=https://:8180/realms/quarkus quarkus.oidc.client-id=backend-service quarkus.oidc.credentials.secret=secret # Tell Dev Services for Keycloak to import the realm file # This property is not effective when running the application in JVM or native modes quarkus.keycloak.devservices.realm-path=quarkus-realm.json
其中
-
%prod.quarkus.oidc.auth-server-url
设置 OpenID Connect (OIDC) 服务器的基本 URL。%prod.
配置文件前缀确保您在开发(dev)模式下运行应用程序时,Dev Services for Keycloak
会启动一个容器。有关更多信息,请参阅在开发模式下运行应用程序部分。 -
quarkus.oidc.client-id
设置一个客户端 ID,用于标识应用程序。 -
quarkus.oidc.credentials.secret
设置客户端密钥,该密钥由client_secret_basic
身份验证方法使用。
有关更多信息,请参阅 Quarkus OpenID Connect (OIDC) 配置属性指南。
启动并配置 Keycloak 服务器
-
将 realm 配置文件放在类路径(
target/classes
目录)上,以便在开发模式下运行时自动导入。如果您已经构建了一个 完整的解决方案,则无需执行此操作,在这种情况下,此 realm 文件将在构建期间添加到类路径。在开发模式下运行应用程序时,请勿启动 Keycloak 服务器;
Dev Services for Keycloak
将启动一个容器。有关更多信息,请参阅在开发模式下运行应用程序部分。 -
要启动 Keycloak 服务器,您可以使用 Docker 运行以下命令
docker run --name keycloak -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
-
其中
keycloak.version
设置为26.2.4
或更高版本。
-
-
您可以在 localhost:8180 访问您的 Keycloak 服务器。
-
要访问 Keycloak 管理控制台,请使用以下登录凭据以
admin
用户身份登录-
用户名:
admin
-
密码:
admin
-
-
从上游社区存储库导入 realm 配置文件以创建一个新的 realm。
有关更多信息,请参阅 Keycloak 文档中关于创建和配置新 realm的内容。
要通过使用 Keycloak Admin Client 从您的应用程序配置 Keycloak 服务器,请根据您的设置包含以下扩展程序之一
这些指南确保 Keycloak Admin Client 与您的 REST 框架无缝集成,无论您是使用 REST 服务器、REST 客户端还是两者。 有关更多信息,请参阅 Quarkus Keycloak Admin Client 指南。 |
在开发模式下运行应用程序
-
要在开发模式下运行应用程序,请运行以下命令
CLIquarkus dev
Maven./mvnw quarkus:dev
Gradle./gradlew --console=plain quarkusDev
-
Dev Services for Keycloak 将启动一个 Keycloak 容器并导入一个
quarkus-realm.json
。
-
-
打开一个 Dev UI,您可以在 /q/dev-ui 中找到它。然后,在
OpenID Connect
卡中,单击Keycloak provider
链接。 -
当提示您登录到
OpenID Connect Dev UI
提供的Single Page Application
时,请执行以下步骤-
以
alice
(密码:alice
)身份登录,她具有user
角色。-
访问
/api/admin
返回403
状态代码。 -
访问
/api/users/me
返回200
状态代码。
-
-
注销并以
admin
(密码:admin
)身份再次登录,他同时具有admin
和user
角色。-
访问
/api/admin
返回200
状态代码。 -
访问
/api/users/me
返回200
状态代码。
-
-
在 JVM 模式下运行应用程序
完成开发模式后,您可以将应用程序作为标准 Java 应用程序运行。
-
编译应用程序
CLIquarkus build
Maven./mvnw install
Gradle./gradlew build
-
运行应用程序
java -jar target/quarkus-app/quarkus-run.jar
在原生模式下运行应用程序
您可以将此相同的演示按原样编译为原生模式,而无需进行任何修改。这意味着您不再需要在生产环境中安装 JVM。运行时技术包含在生成的二进制文件中,并经过优化,可以以最少的资源运行。
编译需要一段时间,因此默认情况下禁用此步骤。
-
通过启用
native
配置文件再次构建您的应用程序CLIquarkus build --native
Maven./mvnw install -Dnative
Gradle./gradlew build -Dquarkus.native.enabled=true
-
稍等片刻后,您可以直接运行以下二进制文件
./target/security-openid-connect-quickstart-1.0.0-SNAPSHOT-runner
测试应用程序
有关在开发模式下测试您的应用程序的信息,请参阅前面的在开发模式下运行应用程序部分。
您可以使用 curl
测试在 JVM 或原生模式下启动的应用程序。
-
由于应用程序使用 Bearer 令牌认证,因此您必须首先从 Keycloak 服务器获取访问令牌才能访问应用程序资源
export access_token=$(\
curl --insecure -X POST https://:8180/realms/quarkus/protocol/openid-connect/token \
--user backend-service:secret \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'username=alice&password=alice&grant_type=password' | jq --raw-output '.access_token' \
)
当
|
前面的示例获取用户 alice
的访问令牌。
-
任何用户都可以访问
https://:8080/api/users/me
端点,该端点返回一个 JSON 有效负载,其中包含有关用户的详细信息。
curl -v -X GET \
https://:8080/api/users/me \
-H "Authorization: Bearer "$access_token
-
只有具有
admin
角色的用户才能访问https://:8080/api/admin
端点。如果您尝试使用先前颁发的访问令牌访问此端点,您将收到服务器的403
响应。
curl -v -X GET \
https://:8080/api/admin \
-H "Authorization: Bearer "$access_token
-
要访问管理端点,请获取
admin
用户的令牌
export access_token=$(\
curl --insecure -X POST https://:8180/realms/quarkus/protocol/openid-connect/token \
--user backend-service:secret \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'username=admin&password=admin&grant_type=password' | jq --raw-output '.access_token' \
)
有关编写依赖于 Dev Services for Keycloak
的集成测试的信息,请参阅“OpenID Connect (OIDC) Bearer 令牌认证”指南的 Dev Services for Keycloak 部分。