使用基本身份验证和 Jakarta Persistence 开始使用安全性
通过使用内置的 Quarkus 基本身份验证和 Jakarta Persistence 身份提供程序保护您的 Quarkus 应用程序端点,从而开始使用 Quarkus Security,从而启用基于角色的访问控制。
Jakarta Persistence IdentityProvider
验证 基本身份验证 用户名和密码对,并将其转换为 SecurityIdentity
实例,该实例用于授权访问请求,从而保护您的 Quarkus 应用程序的安全。
有关 Jakarta Persistence 的更多信息,请参阅Quarkus Security with Jakarta Persistence 指南。
本教程将帮助您在 Quarkus 中实现更高级的安全机制,例如,如何使用 OpenID Connect (OIDC) 身份验证机制。
先决条件
要完成本指南,您需要
-
大约 15 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
如果您想使用它,可以选择 Quarkus CLI
-
如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置
构建您的应用程序
本教程详细介绍了如何创建一个具有端点的应用程序,这些端点说明了各种授权策略
端点 | 描述 |
---|---|
|
无需身份验证即可访问,此端点允许匿名访问。 |
|
通过基于角色的访问控制 (RBAC) 保护,此端点仅供具有 |
|
也受到 RBAC 的保护,此端点仅供具有 |
1. 创建并验证 Maven 项目
为了让 Quarkus Security 能够将您的安全源映射到 Jakarta Persistence 实体,请确保本教程中的 Maven 项目包含 quarkus-security-jpa
或 quarkus-security-jpa-reactive
扩展。
Hibernate ORM with Panache 用于存储您的用户身份,但您也可以使用带有
您还必须添加您首选的数据库连接器库。本示例教程中的说明使用 PostgreSQL 数据库作为身份存储。 |
1.1. 创建 Maven 项目
您可以创建一个新的带有 Security Jakarta Persistence 扩展的 Maven 项目,或者将该扩展添加到现有的 Maven 项目。您可以使用 Hibernate ORM 或 Hibernate Reactive。
1.1.1. 创建新的 Maven 项目
-
要创建一个新的带有 Jakarta Persistence 扩展的 Maven 项目,请完成以下步骤之一
-
要创建带有 Hibernate ORM 的 Maven 项目,请使用以下命令
-
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数括在双引号中,例如"-DprojectArtifactId=security-jpa-quickstart"
1.1.2. 将 Jakarta Persistence 扩展添加到现有项目
-
要将 Jakarta Persistence 扩展添加到现有的 Maven 项目,请完成以下步骤之一
-
要将 Security Jakarta Persistence 扩展添加到带有 Hibernate ORM 的现有 Maven 项目,请从您的项目基本目录运行以下命令
CLIquarkus extension add security-jpa
Maven./mvnw quarkus:add-extension -Dextensions='security-jpa'
Gradle./gradlew addExtension --extensions='security-jpa'
-
要将 Security Jakarta Persistence 扩展添加到带有 Hibernate Reactive 的现有 Maven 项目,请从您的项目基本目录运行以下命令
CLIquarkus extension add security-jpa-reactive
Maven./mvnw quarkus:add-extension -Dextensions='security-jpa-reactive'
Gradle./gradlew addExtension --extensions='security-jpa-reactive'
-
1.2. 验证 quarkus-security-jpa 依赖项
在您运行上述任一命令以创建 Maven 项目后,请验证 quarkus-security-jpa
依赖项是否已添加到您的项目构建 XML 文件中。
-
要验证
quarkus-security-jpa
扩展,请检查以下配置pom.xml<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-security-jpa</artifactId> </dependency>
build.gradleimplementation("io.quarkus:quarkus-security-jpa")
-
要验证
quarkus-security-jpa-reactive
扩展,请检查以下配置pom.xml<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-security-jpa-reactive</artifactId> </dependency>
build.gradleimplementation("io.quarkus:quarkus-security-jpa-reactive")
2. 编写应用程序
-
通过使用以下方法之一来保护 API 端点,以确定谁可以访问应用程序
-
实现
/api/public
端点以允许所有用户访问应用程序。将常规 Jakarta REST 资源添加到您的 Java 源代码,如以下代码片段所示src/main/java/org/acme/security/jpa/PublicResource.java
package org.acme.security.jpa; import jakarta.annotation.security.PermitAll; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; @Path("/api/public") public class PublicResource { @GET @PermitAll @Produces(MediaType.TEXT_PLAIN) public String publicResource() { return "public"; } }
-
实现一个只能由具有 admin 角色的用户访问的 /api/admin 端点。
/api/admin
端点的源代码类似,但您可以使用@RolesAllowed
注释来确保只有被授予admin
角色的用户才能访问该端点。添加一个带有以下@RolesAllowed
注释的 Jakarta REST 资源src/main/java/org/acme/security/jpa/AdminResource.java
package org.acme.security.jpa; 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 adminResource() { return "admin"; } }
-
实现一个只能由具有
user
角色的用户访问的/api/users/me
端点。使用SecurityContext
来访问当前经过身份验证的Principal
用户并返回他们的用户名,所有这些都从数据库中检索。src/main/java/org/acme/security/jpa/UserResource.java
package org.acme.security.jpa; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.SecurityContext; @Path("/api/users") public class UserResource { @GET @RolesAllowed("user") @Path("/me") public String me(@Context SecurityContext securityContext) { return securityContext.getUserPrincipal().getName(); } }
-
3. 定义用户实体
通过将以下注释添加到 user
实体来指定安全信息在模型中的存储方式
src/main/java/org/acme/security/jpa/User.java
package org.acme.security.jpa;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import io.quarkus.elytron.security.common.BcryptUtil;
import io.quarkus.security.jpa.Password;
import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;
@Entity
@Table(name = "test_user")
@UserDefinition (1)
public class User extends PanacheEntity {
@Username (2)
public String username;
@Password (3)
public String password;
@Roles (4)
public String role;
/**
* Adds a new user to the database
* @param username the username
* @param password the unencrypted password (it is encrypted with bcrypt)
* @param role the comma-separated roles
*/
public static void add(String username, String password, String role) { (5)
User user = new User();
user.username = username;
user.password = BcryptUtil.bcryptHash(password);
user.role = role;
user.persist();
}
}
只有当单个实体使用 @UserDefinition
注释时,才会初始化 quarkus-security-jpa
扩展。
1 | @UserDefinition 注释必须存在于单个实体上,无论是常规 Hibernate ORM 实体还是带有 Panache 的 Hibernate ORM 实体。 |
2 | 指示用于用户名字段。 |
3 | 指示用于密码的字段。默认情况下,它使用 bcrypt 哈希密码。您可以将其配置为使用纯文本或自定义密码。 |
4 | 指示添加到目标主体表示属性的逗号分隔的角色列表。 |
5 | 允许我们在使用适当的 bcrypt 哈希值哈希密码的同时添加用户。 |
不要忘记设置 Panache 和 PostgreSQL JDBC 驱动程序,请参阅设置和配置带有 Panache 的 Hibernate ORM 以获取更多信息。 |
Hibernate Reactive Panache 使用 |
4. 配置应用程序
-
通过将
quarkus.http.auth.basic
属性设置为true
来启用内置的 Quarkus 基本身份验证机制quarkus.http.auth.basic=true
当需要安全访问且未启用其他身份验证机制时,Quarkus 的内置基本身份验证是后备身份验证机制。因此,在本教程中,您不需要将属性
quarkus.http.auth.basic
设置为true
。 -
在
src/main/resources/application.properties
文件中配置至少一个数据源,以便quarkus-security-jpa
扩展可以访问您的数据库。例如src/main/resources/application.propertiesquarkus.http.auth.basic=true %prod.quarkus.datasource.db-kind=postgresql %prod.quarkus.datasource.username=quarkus %prod.quarkus.datasource.password=quarkus %prod.quarkus.datasource.jdbc.url=jdbc:postgresql:quarkus quarkus.hibernate-orm.schema-management.strategy=drop-and-create
通过添加
%prod.
配置文件前缀,您可以确保数据源属性仅由在生产模式下运行的应用程序观察到。 -
要使用用户和角色初始化数据库,请实现
Startup
类,如以下代码片段中所述
|
src/main/java/org/acme/security/jpa/Startup.java
package org.acme.security.jpa;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Singleton;
import jakarta.transaction.Transactional;
import io.quarkus.runtime.StartupEvent;
@Singleton
public class Startup {
@Transactional
public void loadUsers(@Observes StartupEvent evt) {
// reset and load all test users
User.deleteAll();
User.add("admin", "admin", "admin");
User.add("user", "user", "user");
}
}
前面的示例演示了如何保护应用程序以及如何提供由指定数据库提供的身份。
在生产环境中,不要存储纯文本密码。因此, |
5. 使用适用于 PostgreSQL 的 Dev Services 在开发模式下测试您的应用程序
在使用生产模式运行应用程序之前,请使用适用于 PostgreSQL 的 Dev Services完成 JVM 和本机模式下的应用程序集成测试。
首先将以下依赖项添加到您的测试项目中
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.rest-assured:rest-assured")
要在开发模式下运行您的应用程序
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
在这种情况下,适用于 PostgreSQL 的 Dev Services
启动并配置一个 PostgreSQL
测试容器。确保您的计算机上安装了 Podman
或 Docker
。
要编写集成测试,请使用以下代码示例
src/test/java/org/acme/security/jpa/JpaSecurityRealmTest.java
package org.acme.security.jpa;
import static io.restassured.RestAssured.get;
import static io.restassured.RestAssured.given;
import static org.hamcrest.core.Is.is;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
public class JpaSecurityRealmTest {
@Test
void shouldAccessPublicWhenAnonymous() {
get("/api/public")
.then()
.statusCode(HttpStatus.SC_OK);
}
@Test
void shouldNotAccessAdminWhenAnonymous() {
get("/api/admin")
.then()
.statusCode(HttpStatus.SC_UNAUTHORIZED);
}
@Test
void shouldAccessAdminWhenAdminAuthenticated() {
given()
.auth().preemptive().basic("admin", "admin")
.when()
.get("/api/admin")
.then()
.statusCode(HttpStatus.SC_OK);
}
@Test
void shouldNotAccessUserWhenAdminAuthenticated() {
given()
.auth().preemptive().basic("admin", "admin")
.when()
.get("/api/users/me")
.then()
.statusCode(HttpStatus.SC_FORBIDDEN);
}
@Test
void shouldAccessUserAndGetIdentityWhenUserAuthenticated() {
given()
.auth().preemptive().basic("user", "user")
.when()
.get("/api/users/me")
.then()
.statusCode(HttpStatus.SC_OK)
.body(is("user"));
}
}
如您在此代码示例中所见,您无需从测试代码启动测试容器。
要运行这些测试,请选择 Press [r] to resume testing
选项,该选项在您在开发模式下启动应用程序后显示在控制台中。
当您在开发模式下启动应用程序时,适用于 PostgreSQL 的 Dev Services 会启动一个 PostgreSQL 开发模式容器,以便您可以开始开发您的应用程序。在开发应用程序时,您可以使用Continuous Testing功能单独添加和运行测试。适用于 PostgreSQL 的 Dev Services 支持在您开发时进行测试,方法是提供一个单独的 PostgreSQL 测试容器,该容器与开发模式容器不冲突。 |
或者,您可以使用 Maven 运行这些测试
./mvnw test
6. 使用 Curl 或浏览器在生产模式下测试您的应用程序
要使用 Curl 或浏览器测试您的应用程序,请首先启动 PostgreSQL 服务器。然后,在 JVM 或本机模式下编译并运行您的应用程序。
6.1. 启动 PostgreSQL 服务器
docker run --rm=true --name security-getting-started -e POSTGRES_USER=quarkus \
-e POSTGRES_PASSWORD=quarkus -e POSTGRES_DB=quarkus \
-p 5432:5432 postgres:17
6.2. 编译并运行应用程序
-
通过使用以下方法之一来编译并运行您的 Quarkus 应用程序
-
JVM 模式
-
编译应用程序
CLIquarkus build
Maven./mvnw install
Gradle./gradlew build
-
运行应用程序
java -jar target/quarkus-app/quarkus-run.jar
-
-
本机模式
-
编译应用程序
CLIquarkus build --native
Maven./mvnw install -Dnative
Gradle./gradlew build -Dquarkus.native.enabled=true
-
运行应用程序
./target/security-jpa-quickstart-1.0.0-SNAPSHOT-runner
-
-
6.3. 使用 Curl 访问并测试应用程序安全性
当您的应用程序正在运行时,您可以使用以下 Curl 命令之一来访问其端点。
-
以匿名方式连接到受保护的端点
$ curl -i -X GET https://:8080/api/public HTTP/1.1 200 OK Content-Length: 6 Content-Type: text/plain;charset=UTF-8 public
-
以匿名方式连接到受保护的端点
$ curl -i -X GET https://:8080/api/admin HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic
-
以授权用户身份连接到受保护的端点
$ curl -i -X GET -u admin:admin https://:8080/api/admin HTTP/1.1 200 OK Content-Length: 5 Content-Type: text/plain;charset=UTF-8 admin
您也可以使用浏览器访问相同的端点 URL。
6.5. 结果
当您提供授权用户的凭据(例如,admin:admin
)时,Jakarta Persistence 安全扩展会进行身份验证并加载用户的角色。admin
用户有权访问受保护的资源。
如果资源受到 @RolesAllowed("user")
的保护,则用户 admin
无权访问该资源,因为它未分配给“user”角色,如以下示例所示
$ curl -i -X GET -u admin:admin https://:8080/api/users/me
HTTP/1.1 403 Forbidden
最后,名为 user
的用户已获得授权,并且安全上下文包含主要详细信息,例如用户名。
$ curl -i -X GET -u user:user https://:8080/api/users/me
HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/plain;charset=UTF-8
user
下一步是什么
您已成功学习了如何创建和测试安全的 Quarkus 应用程序。这是通过将 Quarkus 中内置的基本身份验证与 Jakarta Persistence 身份提供程序集成来实现的。
完成本教程后,您可以在 Quarkus 中探索更高级的安全机制。以下信息向您展示了如何使用 OpenID Connect
安全地单点登录到您的 Quarkus 端点