编辑此页面

具有 Jakarta Persistence 的 Quarkus Security

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

Quarkus 提供了一个 Jakarta Persistence 身份提供程序,类似于 JDBC 身份提供程序。Jakarta Persistence 适用于 Basic基于表单 的 Quarkus 安全机制,这些机制需要用户名和密码凭据。

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

有关实际示例,请参阅 使用 Basic 身份验证和 Jakarta Persistence 入门安全 教程。

Jakarta Persistence 实体规范

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

以下 Jakarta Persistence 实体规范演示了用户的身份信息需要如何存储在 Jakarta Persistence 实体中并正确映射,以便 Quarkus 可以从数据库中检索这些信息。

  • @UserDefinition 注释必须存在于 Jakarta Persistence 实体上,无论是否使用了 简化的 Hibernate ORM with Panache

  • @Username@Password 字段类型始终是 String

  • @Roles 字段必须是 StringCollection<String>,或者 Collection<X>,其中 X 是一个实体类,其中包含一个用 @RolesValue 注释的单个 String 字段。

  • 每个 String 角色元素类型都将解析为逗号分隔的角色列表。

以下示例通过向 user 实体添加注释来演示存储安全信息

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") (1)
@UserDefinition (2)
public class User extends PanacheEntity {
    @Username (3)
    public String username;
    @Password (4)
    public String password;
    @Roles (5)
    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) { (6)
        User user = new User();
        user.username = username;
        user.password = BcryptUtil.bcryptHash(password);
        user.role = role;
        user.persist();
    }
}

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

1 表名。不要将其定义为 user,因为 user 是大多数数据库中的受限关键字。
2 @UserDefinition 注释必须存在于单个实体上,该实体可以是常规的 Hibernate ORM 实体,也可以是 Hibernate ORM with Panache 实体。
3 指示用于用户名的字段。
4 指示用于密码的字段。默认情况下,quarkus-security-jpa 使用 bcrypt 哈希密码,您也可以配置纯文本或自定义密码。
5 这指示了添加到目标主体表示属性的角色列表,用逗号分隔。
6 此方法允许您在哈希密码时使用适当的 bcrypt 哈希来添加用户。

将 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;
}

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

密码存储和哈希

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

使用默认选项时,密码将使用 bcryptModular Crypt Format (MCF) 下存储和哈希。在使用 MCF 时,哈希算法、迭代次数和盐都作为哈希值的一部分存储。因此,我们不需要专用的列来存储它们。

在密码学中,盐(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;
}
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);
    }
}

要快速创建哈希密码,请使用 String BcryptUtil.bcryptHash(String password),它默认创建随机盐并在十次迭代中哈希。此方法还允许指定迭代次数和使用的盐。

对于在生产环境中运行的应用程序,请勿以纯文本形式存储密码。

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

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

构建时固定的配置属性 - 所有其他配置属性都可以在运行时覆盖

配置属性

类型

默认

选择 Hibernate ORM 持久化单元。未指定值时使用默认持久化单元。

环境变量:QUARKUS_SECURITY_JPA_PERSISTENCE_UNIT_NAME

显示更多

字符串

<默认>

相关内容