Getting started with Security by using Basic authentication and Jakarta Persistence
Get started with Quarkus Security by securing your Quarkus application endpoints with the built-in Quarkus Basic authentication and the Jakarta Persistence identity provider, enabling role-based access control.
The Jakarta Persistence IdentityProvider
verifies and converts a Basic authentication user name and password pair to a SecurityIdentity
instance, which is used to authorize access requests, making your Quarkus application secure.
Para obter mais informações sobre o Jakarta Persistence, consulte o guia Quarkus Security com Jakarta Persistence .
This tutorial prepares you to implement more advanced security mechanisms in Quarkus, for example, how to use the OpenID Connect (OIDC) authentication mechanism.
Pré-requisitos
Para concluir este guia, você precisa:
-
Cerca de 15 minutos
-
Um IDE
-
JDK 17+ installed with
JAVA_HOME
configured appropriately -
Apache Maven 3.9.9
-
Opcionalmente, o Quarkus CLI se você quiser usá-lo
-
Opcionalmente, Mandrel ou GraalVM instalado e configurado apropriadamente se você quiser criar um executável nativo (ou Docker se você usar uma compilação de contêiner nativo)
Building your application
This tutorial gives detailed steps for creating an application with endpoints that illustrate various authorization policies:
Endpoint | Descrição |
---|---|
|
Accessible without authentication, this endpoint allows anonymous access. |
|
Secured with role-based access control (RBAC), this endpoint is accessible only to users with the |
|
Also secured by RBAC, this endpoint is accessible only to users with the |
1. Crie e verifique o projeto Maven
For Quarkus Security to be able to map your security source to Jakarta Persistence entities, ensure that the Maven project in this tutorial includes the quarkus-security-jpa
or quarkus-security-jpa-reactive
extension.
Hibernate ORM with Panache is used to store your user identities, but you can also use Hibernate ORM with the Both Hibernate Reactive and Hibernate Reactive with Panache can be used with the Você também deve adicionar sua biblioteca de conector de banco de dados preferida. As instruções neste tutorial de exemplo usam um banco de dados PostgreSQL para o armazenamento de identidade. |
1.1. Crie o projeto Maven
You can create a new Maven project with the Security Jakarta Persistence extension or add the extension to an existing Maven project. You can use either Hibernate ORM or Hibernate Reactive.
1.1.1. Creating new Maven project
-
Para criar um novo projeto Maven com a extensão Jakarta Persistence, conclua uma das etapas a seguir:
-
Para criar o projeto Maven com o Hibernate ORM, use o seguinte comando:
-
Para usuários do Windows:
-
Se estiver usando cmd, (não use barra invertida '\' e coloque tudo na mesma linha)
-
Se estiver usando o Powershell, envolva os parâmetros '-D' entre aspas duplas, por exemplo, '"-DprojectArtifactId=security-jpa-quickstart"'
1.1.2. Adding Jakarta Persistence extension to existing project
-
Para adicionar a extensão Jakarta Persistence a um projeto Maven existente, conclua uma das etapas a seguir:
-
Para adicionar a extensão Security Jakarta Persistence a um projeto Maven existente com o Hibernate ORM, execute o seguinte comando no diretório base do projeto:
CLIquarkus extension add security-jpa
Maven./mvnw quarkus:add-extension -Dextensions='security-jpa'
Gradle./gradlew addExtension --extensions='security-jpa'
-
Para adicionar a extensão Security Jakarta Persistence a um projeto Maven existente com o Hibernate Reativo, execute o seguinte comando no diretório base do projeto:
CLIquarkus extension add security-jpa-reactive
Maven./mvnw quarkus:add-extension -Dextensions='security-jpa-reactive'
Gradle./gradlew addExtension --extensions='security-jpa-reactive'
-
1.2. Verifique a dependência do quarkus-security-jpa
After you have run either of the preceding commands to create the Maven project, verify that the quarkus-security-jpa
dependency was added to your project build XML file.
-
To verify the
quarkus-security-jpa
extension, check for the following configuration:pom.xml<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-security-jpa</artifactId> </dependency>
build.gradleimplementation("io.quarkus:quarkus-security-jpa")
-
To verify the
quarkus-security-jpa-reactive
extension, check for the following configuration:pom.xml<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-security-jpa-reactive</artifactId> </dependency>
build.gradleimplementation("io.quarkus:quarkus-security-jpa-reactive")
2. Escreva a aplicação
-
Proteja o endpoint da API para determinar quem pode acessar a aplicação usando uma das seguintes abordagens:
-
Implemente o endpoint
/api/public
para permitir que todos os usuários acessem a aplicação. Adicione um recurso Jakarta REST regular ao seu código-fonte Java, conforme mostrado no trecho de código a seguir: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"; } }
-
Implement an /api/admin endpoint that can only be accessed by users who have the admin role. The source code for the
/api/admin
endpoint is similar, but instead, you use a@RolesAllowed
annotation to ensure that only users granted theadmin
role can access the endpoint. Add a Jakarta REST resource with the following@RolesAllowed
annotation: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"; } }
-
Implemente um endpoint
/api/users/me
que só possa ser acessado por usuários que tenham a funçãouser
. UseSecurityContext
para obter acesso ao usuárioPrincipal
autenticado no momento e para retornar o nome de usuário dele, que é recuperado do banco de dados.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(); } }
-
3. Defina a entidade do usuário
-
Agora, você pode descrever como deseja que as informações de segurança sejam armazenadas no modelo, adicionando anotações à entidade
user
, conforme descrito no seguinte trecho de código:
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();
}
}
The quarkus-security-jpa
extension only initializes 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 | Indica o campo usado para o nome de usuário. |
3 | Indica o campo usado para a senha. Por padrão, ele usa senhas com hash bcrypt. Você pode configurá-lo para usar texto em claro ou senhas personalizadas. |
4 | Indica a lista separada por vírgulas de funções adicionadas aos atributos de representação do principal de destino. |
5 | Permite-nos adicionar usuários enquanto fazemos o hash das senhas com o hash bcrypt adequado. |
Don’t forget to set up the Panache and PostgreSQL JDBC driver, please see Setting up and configuring Hibernate ORM with Panache for more information. |
O Hibernate Reactive Panache usa |
4. Configure a aplicação
-
Ative o mecanismo de autenticação básico do Quarkus integrado definindo a propriedade
quarkus.http.auth.basic
comotrue
:quarkus.http.auth.basic=true
When secure access is required, and no other authentication mechanisms are enabled, the built-in Basic authentication of Quarkus is the fallback authentication mechanism. Therefore, in this tutorial, you do not need to set the property
quarkus.http.auth.basic
totrue
. -
Configure at least one data source in the
application.properties
file so thequarkus-security-jpa
extension can access your database. For example: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
-
Para inicializar o banco de dados com usuários e funções, implemente a classe
Startup
, conforme descrito no trecho de código a seguir:
|
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");
}
}
O exemplo anterior demonstra como a aplicação pode ser protegida e as identidades fornecidas pelo banco de dados especificado.
In a production environment, do not store plain text passwords.
As a result, the |
5. Teste sua aplicação usando o Dev Services para PostgreSQL
Conclua o teste de integração da sua aplicação nos modos JVM e nativo usando o Dev Services para PostgreSQL antes de executar a aplicação no modo de produção.
Start by adding the following dependencies to your test project:
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.rest-assured:rest-assured")
Para executar sua aplicação no modo de desenvolvimento:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
The following properties configuration demonstrates how to enable PostgreSQL testing to run only in production (prod
) mode.
In this scenario, Dev Services for PostgreSQL
launches and configures a PostgreSQL
test container.
%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
Se você adicionar o prefixo de perfil %prod.
, as propriedades da fonte de dados não estarão visíveis em Dev Services para PostgreSQL
e só serão observadas por uma aplicação em execução no modo de produção.
Para escrever o teste de integração, use o exemplo de código a seguir:
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"));
}
}
Como você pode ver neste exemplo de código, não é necessário iniciar o contêiner de teste a partir do código de teste.
When you start your application in dev mode, Dev Services for PostgreSQL launches a PostgreSQL dev mode container so that you can start developing your application. While developing your application, you can add and run tests individually by using the Continuous Testing feature. Dev Services for PostgreSQL supports testing while you develop by providing a separate PostgreSQL test container that does not conflict with the dev mode container. |
6. Test your application using Curl or browser
To test your application using Curl or the browser, you must first start a PostgreSQL server, then compile and run your application either in JVM or native mode.
6.1. Start the PostgreSQL server
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
6.2. Compile e execute a aplicação
-
Compile e execute sua aplicação Quarkus usando um dos métodos a seguir:
-
Modo JVM
-
Compile a aplicação:
CLIquarkus build
Maven./mvnw install
Gradle./gradlew build
-
Execute a aplicação:
java -jar target/quarkus-app/quarkus-run.jar
-
-
Modo nativo
-
Compile a aplicação:
CLIquarkus build --native
Maven./mvnw install -Dnative
Gradle./gradlew build -Dquarkus.native.enabled=true
-
Execute a aplicação:
./target/security-jpa-quickstart-1.0.0-SNAPSHOT-runner
-
-
6.3. Access and test the application security with Curl
Quando a aplicação está em execução, você pode acessar seus endpoints usando um dos seguintes comandos Curl.
-
Conecte-se a um endpoint protegido de forma anônima:
$ 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
-
Conecte-se a um endpoint protegido de forma anônima:
$ 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
-
Conecte-se a um endpoint protegido como um usuário autorizado:
$ 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
Você também pode acessar os mesmos URLs de endpoint usando um navegador.
6.4. Access and test the application security with the browser
If you use a browser to connect to a protected resource anonymously, a Basic authentication form displays, prompting you to enter credentials.
6.5. Resultados
When you provide the credentials of an authorized user, for example, admin:admin
, the Jakarta Persistence security extension authenticates and loads the user’s roles.
The admin
user is authorized to access the protected resources.
If a resource is protected with @RolesAllowed("user")
, the user admin
is not authorized to access the resource because it is not assigned to the "user" role, as shown in the following example:
$ 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
Finally, the user named user
is authorized, and the security context contains the principal details, for example, the username.
$ 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
O que vem a seguir
You have successfully learned how to create and test a secure Quarkus application. This was achieved by integrating the built-in Basic authentication in Quarkus with the Jakarta Persistence identity provider.
Depois de concluir este tutorial, você pode explorar mecanismos de segurança mais avançados no Quarkus. As informações a seguir mostram como usar o OpenID Connect
para obter acesso seguro de login único aos endpoints do Quarkus: