The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

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.6

  • 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

/api/public

Accessible without authentication, this endpoint allows anonymous access.

/api/admin

Secured with role-based access control (RBAC), this endpoint is accessible only to users with the admin role. Access is controlled declaratively by using the @RolesAllowed annotation.

/api/users/me

Also secured by RBAC, this endpoint is accessible only to users with the user role. It returns the caller’s username as a string.

Para examinar o exemplo concluído, faça o download do archive ou clone o repositório Git:

git clone https://github.com/quarkusio/quarkus-quickstarts.git

You can find the solution in the security-jpa-quickstart directory.

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 security-jpa or security-jpa-reactive extension.

Hibernate ORM with Panache is used to store your user identities, but you can also use Hibernate ORM with the security-jpa extension. Both Hibernate Reactive and Hibernate Reactive with Panache can be used with the security-jpa-reactive extension.

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.

  • 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:

CLI
quarkus create app org.acme:security-jpa-quickstart \
    --extension='security-jpa,jdbc-postgresql,rest,hibernate-orm-panache' \
    --no-code
cd security-jpa-quickstart

Para criar um projeto Gradle, adicione a opção --gradle ou --gradle-kotlin-dsl.

Para obter mais informações sobre como instalar e usar a CLI do Quarkus, consulte o guia Quarkus CLI.

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.10.0:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=security-jpa-quickstart \
    -Dextensions='security-jpa,jdbc-postgresql,rest,hibernate-orm-panache' \
    -DnoCode
cd security-jpa-quickstart

Para criar um projeto Gradle, adicione a opção '-DbuildTool=gradle' ou '-DbuildTool=gradle-kotlin-dsl'.

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"'

    • 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:

        CLI
        quarkus 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:

        CLI
        quarkus 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

Depois de executar um dos comandos anteriores para criar o projeto Maven, verifique se a dependência security-jpa foi adicionada ao arquivo XML de construção do projeto.

  • Para verificar a extensão security-jpa, verifique a seguinte configuração:

    pom.xml
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-security-jpa</artifactId>
    </dependency>
    build.gradle
    implementation("io.quarkus:quarkus-security-jpa")
  • Para verificar a extensão security-jpa-reactive, verifique a seguinte configuração:

    pom.xml
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-security-jpa-reactive</artifactId>
    </dependency>
    build.gradle
    implementation("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 the admin 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ção user. Use SecurityContext para obter acesso ao usuário Principal 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 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 io.quarkus.hibernate.reactive.panache.PanacheEntity em vez de io.quarkus.hibernate.orm.panache.PanacheEntity. Para obter mais informações, consulte Arquivo do usuário .

4. Configure a aplicação

  1. Ative o mecanismo de autenticação básico do Quarkus integrado definindo a propriedade quarkus.http.auth.basic como true :

    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 to true.

  2. Configure pelo menos uma fonte de dados no arquivo application.properties para que a extensão security-jpa possa acessar seu banco de dados. Por exemplo:

    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
  3. 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:

  • The URLs of Reactive datasources that are used by the security-jpa-reactive extension are set with the quarkus.datasource.reactive.url configuration property and not the quarkus.datasource.jdbc.url configuration property typically used by JDBC datasources.

    %prod.quarkus.datasource.reactive.url=vertx-reactive:postgresql://localhost:5431/security_jpa
  • In this tutorial, a PostgreSQL database is used for the identity store. Hibernate ORM automatically creates the database schema on startup. This approach is suitable for development but is not recommended for production. Therefore, adjustments are needed in a production environment.

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.

Em um ambiente de produção, não armazene senhas em claro. Como resultado, o security-jpa tem como padrão o uso de senhas com hash bcrypt.

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:

pom.xml
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <scope>test</scope>
</dependency>
build.gradle
testImplementation("io.rest-assured:rest-assured")
  • Para executar sua aplicação no modo de desenvolvimento:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./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:elytron_security_jpa

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.

5.1. Use curl or a browser to test your application

  • Use o exemplo a seguir para iniciar o servidor PostgreSQL:

docker run --rm=true --name security-getting-started -e POSTGRES_USER=quarkus \ -e POSTGRES_PASSWORD=quarkus -e POSTGRES_DB=elytron_security_jpa \ -p 5432:5432 postgres:14.1

5.2. Compile e execute a aplicação

  • Compile e execute sua aplicação Quarkus usando um dos métodos a seguir:

    • Modo JVM

      1. Compile a aplicação:

        CLI
        quarkus build
        Maven
        ./mvnw install
        Gradle
        ./gradlew build
      2. Execute a aplicação:

        java -jar target/quarkus-app/quarkus-run.jar
    • Modo nativo

      1. Compile a aplicação:

        CLI
        quarkus build --native
        Maven
        ./mvnw install -Dnative
        Gradle
        ./gradlew build -Dquarkus.native.enabled=true
      2. Execute a aplicação:

        ./target/security-jpa-quickstart-1.0.0-SNAPSHOT-runner

5.3. Acesse e teste a segurança da aplicação

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.

If you use a browser to connect to a protected resource anonymously, a Basic authentication form displays, prompting you to enter credentials.

5.4. 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:

Conteúdo Relacionado