Quarkus Security with Jakarta Persistence
您可以配置应用程序以使用 Jakarta Persistence 存储用户的身份。
You can configure your application to use Jakarta Persistence to store users' identities.
Quarkus 提供了一个 Jakarta Persistence 身份提供程序,类似于 JDBC identity provider。Jakarta Persistence 适用于使用需要用户名和密码凭据的 Basic和 Form-basedQuarkus 安全机制。
Quarkus provides a Jakarta Persistence identity provider, similar to the JDBC identity provider. Jakarta Persistence is suitable for use with the Basic and Form-based Quarkus Security mechanisms, which require username and password credentials.
Jakarta Persistence `IdentityProvider`创建 `SecurityIdentity`实例。在用户身份验证期间,将使用此实例验证和授权访问请求。
The Jakarta Persistence IdentityProvider
creates a SecurityIdentity
instance. During user authentication, this instance is used to verify and authorize access requests.
For a practical example, see the Getting started with Security using Basic authentication and Jakarta Persistence tutorial.
Jakarta Persistence entity specification
Quarkus 安全功能提供了 Jakarta Persistence 集成,以收集用户名、密码和角色,并将它们存储到 Jakarta Persistence 数据库实体中。
Quarkus security offers a Jakarta Persistence integration to collect usernames, passwords, and roles and store them into Jakarta Persistence database entities.
以下 Jakarta Persistence 实体规范演示了如何将用户的详细信息存储在 Jakarta Persistence 实体中,并正确映射,以便 Quarkus 可以从数据库中检索该信息。
The following Jakarta Persistence entity specification demonstrates how users' information needs to be stored in a Jakarta Persistence entity and correctly mapped so that Quarkus can retrieve this information from a database.
-
The
@UserDefinition
annotation must be present on a Jakarta Persistence entity, regardless of whether simplified Hibernate ORM with Panache is used or not. -
The
@Username
and@Password
field types are alwaysString
. -
The
@Roles
field must either beString
,Collection<String>
, or aCollection<X>
, whereX
is an entity class with a singleString
field annotated as@RolesValue
. -
Each
String
role element type is parsed as a comma-separated list of roles.
以下示例演示如何通过向 `user`实体添加注释来存储安全信息:
The following example demonstrates storing security information by adding annotations to the user
entity:
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`扩展。
The quarkus-security-jpa
extension initializes only if a single entity is annotated with @UserDefinition
.
1 | The @UserDefinition annotation must be present on a single entity, either a regular Hibernate ORM entity or a Hibernate ORM with Panache entity. |
2 | Indicates the field used for the username. |
3 | Indicates the field used for the password.
By default, quarkus-security-jpa uses bcrypt-hashed passwords, or you can configure plain text or custom passwords instead. |
4 | This indicates the comma-separated list of roles added to the target principal representation attributes. |
5 | This method lets you add users while hashing passwords with the proper bcrypt hash. |
Jakarta Persistence entity as storage of roles
使用以下示例将角色存储在另一个 Jakarta Persistence 实体中:
Use the following example to store roles inside another Jakarta Persistence entity:
@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;
}
此示例演示如何存储和访问角色。要更新现有用户或创建新用户,请使用 This example demonstrates storing and accessing roles. To update an existing user or create a new one, annotate |
Password storage and hashing
在使用 Quarkus 开发应用程序时,你可以决定如何管理密码存储和散列。你可以保留 Quarkus 的默认密码和散列设置,也可以手动散列密码。
When developing applications with Quarkus, you can decide how to manage password storage and hashing. You can keep the default password and hashing settings of Quarkus, or you can hash passwords manually.
使用默认选项时,密码会使用 bcrypt在 Modular Crypt Format (MCF) 下存储并散列。在使用 MCF 时,散列算法、迭代计数和盐会作为散列值的一部分进行存储。因此,我们不需要专门的列来保存它们。
With the default option, passwords are stored and hashed with bcrypt under the Modular Crypt Format (MCF). While using MCF, the hashing algorithm, iteration count, and salt are stored as a part of the hashed value. As such, we do not need dedicated columns to keep them.
在密码学中,盐是一个名称,表示用作单向函数(散列数据、密码或密码短语)的附加输入的随机数据。 In cryptography, a salt is a name for random data used as an additional input to a one-way function that hashes data, a password, or a passphrase. |
要表示由不同算法散列的存储在数据库中的密码,请创建一个实现 `org.wildfly.security.password.PasswordProvider`的类,如以下示例所示。
To represent passwords stored in the database that were hashed by different algorithms, create a class that implements org.wildfly.security.password.PasswordProvider
as shown in the following example.
以下代码段展示了如何设置一个自定义密码提供器,该提供器表示使用 SHA256 散列算法散列的密码。
The following snippet shows how to set a custom password provider that represents a password that was hashed with the SHA256 hashing algorithm.
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);
}
}
要快速创建散列密码,请使用 To quickly create a hashed password, use |
对于在生产环境中运行的应用程序,请勿将密码存储为纯文本。
For applications running in a production environment, do not store passwords as plain text.
但是,在测试环境中操作时,可以用 `@Password(PasswordType.CLEAR)`注释将密码存储为纯文本。
However, it is possible to store passwords as plain text with the @Password(PasswordType.CLEAR)
annotation when operating in a test environment.
Hibernate Multitenancy受支持,你可以将用户实体存储在启用了多租户的持久性单元中。但是,如果你的 `io.quarkus.hibernate.orm.runtime.tenant.TenantResolver`必须访问 `io.vertx.ext.web.RoutingContext`以解析请求详细信息,则必须禁用主动身份验证。有关主动身份验证的详细信息,请参阅 Quarkus Proactive authentication指南。 The Hibernate Multitenancy is supported, and you can store the user entity in a persistence unit with enabled multitenancy.
However, if your |
Unresolved directive in security-jpa.adoc - include::{generated-dir}/config/quarkus-security-jpa.adoc[]