安全入门


Red Hat build of Quarkus 3.15

Red Hat Customer Content Services

摘要

本指南演示了如何使用基本身份验证和 Jakarta Persistence 保护 Quarkus 应用程序,指导您完成先决条件、应用程序设置和测试。它涵盖了创建 Maven 项目、验证依赖项、编写应用程序端点、定义用户实体和配置基本身份验证。它包括使用 PostgreSQL 的 Dev Services 来测试应用,使用 curl 或浏览器编译、运行和验证应用安全性。最终,您将了解如何实施基于角色的访问控制,准备好进行更高级的机制,如 OIDC。它详细介绍了使用 Jakarta Persistence 进行安全性,包括实体规格、角色存储和密码散列。

向红帽构建的 Quarkus 文档提供反馈

要报告错误或改进文档,请登录您的红帽 JIRA 帐户并提交问题。如果您没有红帽 JIRA 帐户,系统会提示您创建一个帐户。

流程

  1. 单击以下链接 来创建 ticket
  2. Summary 中输入有关此问题的简单描述。
  3. 提供有关 描述 中问题或增强功能的详细描述。包括一个 URL,以在文档中发生问题。
  4. Submit 创建问题并将其路由到适当的文档团队。

使用内置 Quarkus 基本身份验证 和 Jakarta Persistence 身份提供程序保护 Quarkus 应用程序端点,启用基于角色的访问控制。

Jakarta Persistence IdentityProvider 验证并将 基本身份验证 用户名和密码对转换为 SecurityIdentity 实例,该实例用于授权访问请求,从而使 Quarkus 应用程序安全。

有关 Jakarta Persistence 的更多信息,请参阅使用 Jakarta Persistence 的 Quarkus 安全性指南。

本教程准备在 Quarkus 中实施更高级的安全机制,例如如何使用 OpenID Connect (OIDC)身份验证机制。

1.1. 先决条件

要完成本指南,您需要:

1.2. 构建应用程序

本教程提供了使用端点创建应用程序的详细步骤,以说明各种授权策略:

Expand
端点描述

/api/public

此端点无需身份验证即可访问,此端点允许匿名访问。

/api/admin

使用基于角色的访问控制(RBAC)进行保护,此端点只能被具有 admin 角色的用户访问。使用 @RolesAllowed 注释,以声明性方式控制访问权限。

/api/users/me

另外,由 RBAC 保护,此端点只能被具有 用户角色 的用户访问。它将调用者的用户名返回为字符串。

提示

要检查完成的示例,请下载 存档或 克隆 Git 存储库:

git clone https://github.com/quarkusio/quarkus-quickstarts.git -b 3.15
Copy to Clipboard Toggle word wrap

您可以在 security-jpa-quickstart 目录中找到 解决方案。

1.3. 创建并验证 Maven 项目

要使 Quarkus 安全能够将您的安全源映射到 Jakarta Persistence 实体,请确保本教程中的 Maven 项目包含 quarkus-security-jpa 扩展。

注意

带有 Panache 的 Hibernate ORM 用于存储您的用户身份,但您也可以使用带有 quarkus-security-jpa 扩展的 Hibernate ORM

您还必须添加您首选的数据库连接器库。本例教程中的说明对身份存储使用 PostgreSQL 数据库。

1.3.1. 创建 Maven 项目

您可以使用 Security Jakarta Persistence 扩展创建新的 Maven 项目,或将扩展添加到现有 Maven 项目中。您可以使用 Hibernate ORM 或 Hibernate Reactive。

1.3.1.1. 创建新的 Maven 项目
  • 要使用 Jakarta Persistence 扩展创建新的 Maven 项目,请完成以下步骤之一:

    • 要使用 Hibernate ORM 创建 Maven 项目,请使用以下命令:
  • 使用 Quarkus CLI:

    quarkus create app org.acme:security-jpa-quickstart \
        --extension='security-jpa,jdbc-postgresql,rest,hibernate-orm-panache' \
        --no-code
    cd security-jpa-quickstart
    Copy to Clipboard Toggle word wrap

    要创建 Gradle 项目,请添加-- gradle or --gradle-kotlin-dsl 选项。

    有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

  • 使用 Maven:

    mvn com.redhat.quarkus.platform:quarkus-maven-plugin:3.15.1:create \
        -DprojectGroupId=org.acme \
        -DprojectArtifactId=security-jpa-quickstart \
        -Dextensions='security-jpa,jdbc-postgresql,rest,hibernate-orm-panache' \
        -DnoCode
    cd security-jpa-quickstart
    Copy to Clipboard Toggle word wrap

    要创建 Gradle 项目,请添加 -DbuildTool=gradle or -DbuildTool=gradle-kotlin-dsl 选项。

对于 Windows 用户:

  • 如果使用 cmd,(不要使用反向斜杠 \ 并将所有内容放在同一行中)
  • 如果使用 Powershell,则双引号中的 wrap -D 参数,如 "-DprojectArtifactId=security-jpa-quickstart"
  • 要将 Jakarta Persistence 扩展添加到现有 Maven 项目中,请完成以下步骤之一:

    • 要将 Security Jakarta Persistence 扩展添加到带有 Hibernate ORM 的现有 Maven 项目中,请从项目基础目录运行以下命令:

      • 使用 Quarkus CLI:

        quarkus extension add security-jpa
        Copy to Clipboard Toggle word wrap
      • 使用 Maven:

        ./mvnw quarkus:add-extension -Dextensions='security-jpa'
        Copy to Clipboard Toggle word wrap
      • 使用 Gradle:

        ./gradlew addExtension --extensions='security-jpa'
        Copy to Clipboard Toggle word wrap

1.3.2. 验证 quarkus-security-jpa 依赖项

运行上述任何一个命令来创建 Maven 项目后,请验证 quarkus-security-jpa 依赖项是否已添加到项目构建 XML 文件中。

  • 要验证 quarkus-security-jpa 扩展,请检查以下配置:

    • 使用 Maven:

      <dependency>
          <groupId>io.quarkus</groupId>
          <artifactId>quarkus-security-jpa</artifactId>
      </dependency>
      Copy to Clipboard Toggle word wrap
    • 使用 Gradle:

      implementation("io.quarkus:quarkus-security-jpa")
      Copy to Clipboard Toggle word wrap

1.4. 编写应用程序

  • 保护 API 端点,以确定谁可以使用以下任一方法访问应用程序:

    • 实施 /api/public 端点,以允许所有用户访问该应用。在您的 Java 源代码中添加常规 Jakarta REST 资源,如以下代码片段中所示:

      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";
         }
      }
      Copy to Clipboard Toggle word wrap
    • 实施 /api/admin 端点,该端点只能由拥有 admin 角色的用户访问。/api/admin 端点的源代码类似,但您可以使用 @RolesAllowed 注释来确保只有被授予 admin 角色的用户才能访问端点。使用以下 @RolesAllowed 注释添加 Jakarta REST 资源:

      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";
          }
      }
      Copy to Clipboard Toggle word wrap
    • 实施 /api/users/me 端点,该端点只能由拥有用户角色的 用户进行访问。使用 SecurityContext 获取当前经过身份验证的用户的访问权限,并返回其用户名,所有用户都从数据库检索。

      package org.acme.security.jpa;
      
      import jakarta.annotation.security.RolesAllowed;
      import jakarta.inject.Inject;
      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();
          }
      }
      Copy to Clipboard Toggle word wrap

1.5. 定义用户实体

  • 现在,您可以通过向 用户 实体添加注解来把安全信息存储在模型中,如以下代码片段中所述:
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();
    }
}
Copy to Clipboard Toggle word wrap

只有在单个实体被标上 @UserDefinition 标注时,quarkus-security-jpa 扩展才会初始化。

1
@UserDefinition 注释必须存在于单个实体上,可以是常规的 Hibernate ORM 实体,也可以是带有 Panache 实体的 Hibernate ORM。
2
表示用于用户名的字段。
3
指明用于密码的字段。默认情况下,它使用 bcrypt-hashed 密码。您可以将其配置为使用纯文本或自定义密码。
4
表示添加到目标主体表示属性中的以逗号分隔的角色列表。
5
允许我们在使用适当的 bcrypt 哈希对密码进行哈希时添加用户。
注意

不要忘记设置 Panache 和 PostgreSQL JDBC 驱动程序,请参阅使用 Panache 设置和配置 Hibernate ORM

1.6. 配置应用程序

  1. 通过将 quarkus.http.auth.basic 属性设置为 true 来启用内置的 Quarkus 基本身份验证 机制:

    quarkus.http.auth.basic=true

    注意

    当需要安全访问时,且不需要启用其他身份验证机制,Quarkus 的内置 基本身份验证 是回退身份验证机制。因此,在本教程中,您不需要将属性 quarkus.http.auth.basic 设置为 true

  2. application.properties 文件中至少配置一个数据源,以便 quarkus-security-jpa 扩展可以访问您的数据库。例如:

    quarkus.http.auth.basic=true
    
    quarkus.datasource.db-kind=postgresql
    quarkus.datasource.username=quarkus
    quarkus.datasource.password=quarkus
    quarkus.datasource.jdbc.url=jdbc:postgresql:security_jpa
    
    quarkus.hibernate-orm.database.generation=drop-and-create
    Copy to Clipboard Toggle word wrap
  3. 要使用用户和角色初始化数据库,请实施 Startup 类,如以下代码片段中所述:
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");
    }
}
Copy to Clipboard Toggle word wrap

前面的示例演示了应用的受保护和身份,由指定数据库提供。

重要

在生产环境中,不要存储纯文本密码。因此,quarkus-security-jpa 默认使用 bcrypt-hashed 密码。

在以生产环境模式运行应用程序前,在 JVM 和原生模式中使用 Dev Services 完成应用程序的集成测试。

首先,将以下依赖项添加到 test 项目中:

  • 使用 Maven:

    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>rest-assured</artifactId>
        <scope>test</scope>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    testImplementation("io.rest-assured:rest-assured")
    Copy to Clipboard Toggle word wrap

以 dev 模式运行应用程序:

  • 使用 Quarkus CLI:

    quarkus dev
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw quarkus:dev
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew --console=plain quarkusDev
    Copy to Clipboard Toggle word wrap

以下属性配置演示了如何使 PostgreSQL 测试仅在生产(prod)模式下运行。在这种情况下,PostgreSQL 的 Dev Services 启动并配置 PostgreSQL 测试容器。

%prod.quarkus.datasource.db-kind=postgresql
%prod.quarkus.datasource.username=quarkus
%prod.quarkus.datasource.password=quarkus
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost/quarkus

quarkus.hibernate-orm.database.generation=drop-and-create
Copy to Clipboard Toggle word wrap

如果您添加 %prod. 配置集前缀,则数据源属性对 PostgreSQL 的 Dev 服务 不可见,且仅在 production 模式下运行的应用程序观察到。

要编写集成测试,请使用以下代码示例:

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"));
    }
}
Copy to Clipboard Toggle word wrap

如此代码示例中所示,您不需要从测试代码启动测试容器。

注意

当您以 dev 模式启动应用程序时,PostgreSQL 的 Dev Services 会启动 PostgreSQL dev 模式容器,以便您开始开发应用程序。在开发应用程序时,您可以使用 持续 测试功能单独添加和运行测试。用于 PostgreSQL 的 Dev Services 支持在开发过程中通过提供与 dev 模式容器不冲突的独立 PostgreSQL 测试容器进行测试。

1.8. 使用 Curl 或浏览器测试应用程序

要使用 Curl 或浏览器来测试您的应用,您必须首先启动 PostgreSQL 服务器,然后以 JVM 或原生模式编译和运行您的应用。

1.8.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:14.1
Copy to Clipboard Toggle word wrap

1.8.2. 编译并运行应用程序

  • 使用以下方法之一编译并运行 Quarkus 应用程序:

    • JVM 模式

      1. 编译应用程序:

        • 使用 Quarkus CLI:

          quarkus build
          Copy to Clipboard Toggle word wrap
        • 使用 Maven:

          ./mvnw install
          Copy to Clipboard Toggle word wrap
        • 使用 Gradle:

          ./gradlew build
          Copy to Clipboard Toggle word wrap
      2. 运行应用程序:

        java -jar target/quarkus-app/quarkus-run.jar
        Copy to Clipboard Toggle word wrap
    • 原生模式

      1. 编译应用程序:

        • 使用 Quarkus CLI:

          quarkus build --native
          Copy to Clipboard Toggle word wrap
        • 使用 Maven:

          ./mvnw install -Dnative
          Copy to Clipboard Toggle word wrap
        • 使用 Gradle:

          ./gradlew build -Dquarkus.native.enabled=true
          Copy to Clipboard Toggle word wrap
      2. 运行应用程序:

        ./target/security-jpa-quickstart-1.0.0-SNAPSHOT-runner
        Copy to Clipboard Toggle word wrap

1.8.3. 使用 Curl 访问并测试应用安全性

当应用程序运行时,您可以使用以下 Curl 命令之一访问其端点。

  • 匿名连接到受保护的端点:

    $ curl -i -X GET http://localhost:8080/api/public
    
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: text/plain;charset=UTF-8
    
    public
    Copy to Clipboard Toggle word wrap
  • 匿名连接到受保护的端点:

    $ curl -i -X GET http://localhost:8080/api/admin
    
    HTTP/1.1 401 Unauthorized
    Content-Length: 14
    Content-Type: text/html;charset=UTF-8
    WWW-Authenticate: Basic
    
    Not authorized
    Copy to Clipboard Toggle word wrap
  • 以授权用户身份连接到受保护的端点:

    $ curl -i -X GET -u admin:admin http://localhost:8080/api/admin
    
    HTTP/1.1 200 OK
    Content-Length: 5
    Content-Type: text/plain;charset=UTF-8
    
    admin
    Copy to Clipboard Toggle word wrap

您还可以使用浏览器访问相同的端点 URL。

1.8.4. 使用浏览器访问并测试应用安全性

如果您以匿名方式使用浏览器连接到受保护的资源,则会显示基本身份验证表单,提示您输入凭证。

1.8.5. 结果

当您提供授权用户的凭证时,如 admin:admin,Jakarta Persistence 安全扩展会验证并加载用户角色。admin 用户有权访问受保护的资源。

如果资源使用 @RolesAllowed ("user") 保护,用户 admin 不会被授权访问该资源,因为它没有分配给"user"角色,如下例所示:

$ curl -i -X GET -u admin:admin http://localhost:8080/api/users/me

HTTP/1.1 403 Forbidden
Content-Length: 34
Content-Type: text/html;charset=UTF-8

Forbidden
Copy to Clipboard Toggle word wrap

最后,名为 user 的用户被授权,安全上下文包含主体详情,例如用户名。

$ curl -i -X GET -u user:user http://localhost:8080/api/users/me

HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/plain;charset=UTF-8

user
Copy to Clipboard Toggle word wrap

1.9. 接下来是什么

您已成功了解如何创建和测试安全 Quarkus 应用程序。这可以通过将 Quarkus 中的内置 基本身份验证 与 Jakarta Persistence 身份提供程序集成来实现。

完成本教程后,您可以在 Quarkus 中探索更高级的安全机制。以下信息演示了如何使用 OpenID Connect 来保护对 Quarkus 端点的单点登录访问:

1.10. 参考

您可以将应用程序配置为使用 Jakarta Persistence 来存储用户身份。

Quarkus 提供 Jakarta Persistence 身份提供程序,类似于 JDBC 身份提供程序。Jakarta Persistence 适用于基于 BasicForm 的 Quarkus 安全机制,这需要用户名和密码凭证。

Jakarta Persistence IdentityProvider 创建一个 SecurityIdentity 实例。在用户身份验证过程中,此实例用于验证和授权访问请求。

有关实际示例,请参阅开始使用基本身份验证和 Jakarta Persistence 指南。

2.1. Jakarta Persistence 实体规格

Quarkus 安全提供了 Jakarta Persistence 集成,用于收集用户名、密码和角色,并将它们存储在 Jakarta Persistence 数据库实体中。

以下 Jakarta Persistence 实体规格演示了如何将用户信息存储在 Jakarta Persistence 实体中,并正确映射,以便 Quarkus 可以从数据库检索此信息。

  • Jakarta Persistence 实体上必须存在 @UserDefinition 注释,无论是否使用 带有 Panache 的简化的 Hibernate ORM
  • @Username@Password 字段类型始终为 String
  • @Roles 字段必须是 StringCollection<String&gt; 或 Collection<X >,其中 X 是带有单个 String 字段的实体类,标记为 @RolesValue
  • 每个 String 角色元素类型都作为以逗号分隔的角色列表解析。

以下示例演示了通过在 用户 实体中添加注解来存储安全信息:

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();
    }
}
Copy to Clipboard Toggle word wrap

只有在单个实体被标上 @UserDefinition 标注时,quarkus-security-jpa 扩展才会初始化。

1
@UserDefinition 注释必须存在于单个实体上,可以是常规的 Hibernate ORM 实体,也可以是带有 Panache 实体的 Hibernate ORM。
2
表示用于用户名的字段。
3
指明用于密码的字段。默认情况下,quarkus-security-jpa 使用 bcrypt-hashed 密码,或者您可以改为配置纯文本或自定义密码。
4
这表示添加到目标主体表示属性中的以逗号分隔的角色列表。
5
这个方法可让您在使用正确的 bcrypt 哈希进行哈希时添加用户。

2.2. Jakarta Persistence 实体作为角色存储

使用以下示例将角色存储在另一个 Jakarta Persistence 实体中:

@UserDefinition
@Table(name = "test_user")
@Entity
public class User extends PanacheEntity {
    @Username
    public String name;

    @Password
    public String pass;

    @ManyToMany
    @Roles
    public List<Role> roles = new ArrayList<>();
}

@Entity
public class Role extends PanacheEntity {

    @ManyToMany(mappedBy = "roles")
    public List<User> users;

    @RolesValue
    public String role;
}
Copy to Clipboard Toggle word wrap
注意

本例演示了存储和访问角色。要更新现有用户或创建新用户,请使用 @Cascade (CascadeType.ALL) 注解 公共 List<Role> 角色,或者选择特定的 CascadeType

2.3. 密码存储和散列

使用 Quarkus 开发应用程序时,您可以决定如何管理密码存储和散列。您可以保留 Quarkus 的默认密码和散列设置,也可以手动哈希密码。

使用默认选项时,密码通过 Modular Crypt 格式 (MCF)下的 bcrypt 存储和散列。在使用 MCF 时,哈希算法、迭代计数和 salt 存储为散列值的一部分。因此,我们不需要专用的列来保留它们。

注意

在加密中,salt 是一个随机数据的名称,用作对数据、密码或密码短语哈希的单向函数的额外输入。

要表示存储在不同算法的数据库中的密码,请创建一个实施 org.wildfly.security.password.PasswordProvider 的类,如下例所示。

以下代码片段演示了如何设置自定义密码提供程序,它代表使用 SHA256 哈希算法哈希的密码。

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import io.quarkus.security.jpa.Password;
import io.quarkus.security.jpa.PasswordType;
import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;

@UserDefinition
@Table(name = "test_user")
@Entity
public class CustomPasswordUserEntity {
    @Id
    @GeneratedValue
    public Long id;

    @Column(name = "username")
    @Username
    public String name;

    @Column(name = "password")
    @Password(value = PasswordType.CUSTOM, provider = CustomPasswordProvider.class)
    public String pass;

    @Roles
    public String role;
}
Copy to Clipboard Toggle word wrap
import jakarta.xml.bind.DatatypeConverter;

import org.wildfly.security.password.Password;
import org.wildfly.security.password.interfaces.SimpleDigestPassword;

import io.quarkus.security.jpa.PasswordProvider;

public class CustomPasswordProvider implements PasswordProvider {
    @Override
    public Password getPassword(String passwordInDatabase) {
        byte[] digest = DatatypeConverter.parseHexBinary(passwordInDatabase);

        // Let the security runtime know that this passwordInDatabase is hashed by using the SHA256 hashing algorithm
        return SimpleDigestPassword.createRaw(SimpleDigestPassword.ALGORITHM_SIMPLE_DIGEST_SHA_256, digest);
    }
}
Copy to Clipboard Toggle word wrap
提示

要快速创建散列化密码,请使用 String BcryptUtil.bcryptHash (String password),它默认为在 10 个迭代中创建随机 salt 和 hash。此方法还允许指定使用的 iterations 和 salt 的数量。

警告

对于在生产环境中运行的应用程序,请不要将密码存储为纯文本。

但是,在测试环境中运行时,可以将密码以纯文本形式存储为 @Password (PasswordType.CLEAR) 注释。

提示

支持 Hibernate 多租户,您可以将用户实体存储在启用了多租户的持久性单元中。但是,如果您的 io.quarkus.hibernate.orm.runtime.tenant.TenantResolver 必须访问 io.vertx.ext.web.RoutingContext 来解析请求详情,您必须禁用主动身份验证。有关主动身份验证的更多信息,请参阅 Quarkus 主动身份验证 指南。

build 时修复的 - 配置属性在构建时修复 - 所有其他配置属性在运行时可覆盖

Expand

配置属性

类型

default

在构建时为 quarkus.security-jpa.persistence-unit-name] quarkus.security-jpa.persistence-unit-name

选择 Hibernate ORM 持久性单元。如果没有指定值,则使用默认持久性单元。

环境变量: QUARKUS_SECURITY_fabric_PERSISTENCE_UNIT_NAME

string

<default>

2.4. 参考

法律通告

Copyright © 2025 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2026 Red Hat
返回顶部