Introdução

A segurança de aplicações web é um aspecto crítico no desenvolvimento de software moderno. Neste tutorial, vamos explorar como implementar sistemas de autenticação robustos com o uso do framework Red, juntamente com bibliotecas populares como JWT (JSON Web Tokens) e OAuth. Faremos uma abordagem passo a passo, começando pela configuração do ambiente até a implementação de autenticação, autorização e testes unitários. Este guia é projetado para desenvolvedores que desejam assegurar suas aplicações web, garantindo que apenas usuários autenticados tenham acesso a recursos protegidos, enquanto também previnem fraudes e acessos indevidos.

Etapas

  1. Configuração do Ambiente de Desenvolvimento

    Antes de começarmos, você deverá ter o JDK (Java Development Kit) e o Maven instalados em sua máquina. Você pode verificar as versões instaladas rodando os seguintes comandos no terminal.

    commands
    # Verificar versões instaladas
    java -version
    mvn -version

  2. Criação do Projeto Spring Boot

    Utilize o Spring Initializr para gerar um novo projeto Spring Boot com as dependências necessárias. Certifique-se de incluir as dependências ‘Spring Web’, ‘Spring Security’, ‘Spring Data JPA’, e ‘jjwt’ para trabalhar com JWT.

    pom.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.example</groupId>
      <artifactId>auth-system</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <name>auth-system</name>
      <description>API de autenticação com JWT e OAuth</description>
      <properties>
        <java.version>11</java.version>
      </properties>
      <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.9.1</version>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
        </dependency>
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    </project>

  3. Configuração do Application Properties

    Edite o arquivo `application.properties` para definir as propriedades do aplicativo, como a configuração do banco de dados e as propriedades de segurança básicas.

    application.properties
    spring.datasource.url=jdbc:mysql://localhost:3306/auth_db
    spring.datasource.username=root
    spring.datasource.password=senha
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true
    

  4. Criação da Entidade `Usuario`

    Implemente a classe modelo `Usuario`, que representará os usuários na aplicação e inclui atributos como email e senha, além de anotações JPA para o mapeamento ao banco de dados.

    Usuario.java
    package com.example.authsystem.model;
    
    import javax.persistence.*;
    
    @Entity
    @Table(name = "usuarios")
    public class Usuario {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false, unique = true)
        private String email;
    
        @Column(nullable = false)
        private String senha;
    
        // Getters e Setters
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public String getSenha() {
            return senha;
        }
    
        public void setSenha(String senha) {
            this.senha = senha;
        }
    }

  5. Criação do Repositório `UsuarioRepository`

    Implemente a interface `UsuarioRepository`, que estende `JpaRepository` e fornece métodos para operações CRUD (Criar, Ler, Atualizar, Deletar) no banco de dados.

    UsuarioRepository.java
    package com.example.authsystem.repository;
    
    import com.example.authsystem.model.Usuario;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface UsuarioRepository extends JpaRepository<Usuario, Long> {
        Usuario findByEmail(String email);
    }

  6. Implementação do Serviço `UsuarioService`

    Crie a classe `UsuarioService` que contém a lógica de negócios para a autenticação, incluindo a geração de JWT e a validação de credenciais.

    UsuarioService.java
    package com.example.authsystem.service;
    
    import com.example.authsystem.model.Usuario;
    import com.example.authsystem.repository.UsuarioRepository;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.stereotype.Service;
    
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    @Service
    public class UsuarioService {
        @Autowired
        private UsuarioRepository usuarioRepository;
    
        public Usuario save(Usuario usuario) {
            usuario.setSenha(new BCryptPasswordEncoder().encode(usuario.getSenha()));
            return usuarioRepository.save(usuario);
        }
    
        public String gerarToken(String email) {
            Map<String, Object> claims = new HashMap<>();
            return Jwts.builder()
                    .setClaims(claims)
                    .setSubject(email)
                    .setIssuedAt(new Date(System.currentTimeMillis()))
                    .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 horas
                    .signWith(SignatureAlgorithm.HS256, "secreta")
                    .compact();
        }
    
        public boolean validarToken(String token, String email) {
            final String usuario = extrairEmail(token);
            return (usuario.equals(email) && !isTokenExpirado(token));
        }
    
        private boolean isTokenExpirado(String token) {
            return extrairExpiracao(token).before(new Date());
        }
    
        private Date extrairExpiracao(String token) {
            return Jwts.parser().setSigningKey("secreta").parseClaimsJws(token).getBody().getExpiration();
        }
    
        private String extrairEmail(String token) {
            return Jwts.parser().setSigningKey("secreta").parseClaimsJws(token).getBody().getSubject();
        }
    }

  7. Implementação do Controlador `AuthController`

    Crie a classe `AuthController` para gerenciar endpoints relacionados à autenticação, como login e registro de usuários.

    AuthController.java
    package com.example.authsystem.controller;
    
    import com.example.authsystem.model.Usuario;
    import com.example.authsystem.service.UsuarioService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping("/api/auth")
    public class AuthController {
        @Autowired
        private UsuarioService usuarioService;
    
        @PostMapping("/register")
        public ResponseEntity<Usuario> registrar(@RequestBody Usuario usuario) {
            return ResponseEntity.ok(usuarioService.save(usuario));
        }
    
        @PostMapping("/login")
        public ResponseEntity<String> login(@RequestBody Usuario usuario) {
            // Aqui você deve adicionar sua lógica de validação de usuário
            String token = usuarioService.gerarToken(usuario.getEmail());
            return ResponseEntity.ok(token);
        }
    }

  8. Implementação de Testes Unitários

    Elabore testes unitários para a classe `UsuarioService`, assegurando que as funções de criação de usuário e geração de JWT funcionem corretamente.

    UsuarioServiceTest.java
    package com.example.authsystem.service;
    
    import com.example.authsystem.model.Usuario;
    import com.example.authsystem.repository.UsuarioRepository;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.MockitoAnnotations;
    
    import static org.junit.jupiter.api.Assertions.*;
    import static org.mockito.Mockito.when;
    
    public class UsuarioServiceTest {
        @InjectMocks
        private UsuarioService usuarioService;
    
        @Mock
        private UsuarioRepository usuarioRepository;
    
        @BeforeEach
        public void init() {
            MockitoAnnotations.openMocks(this);
        }
    
        @Test
        public void testRegistrarUsuario() {
            Usuario usuario = new Usuario();
            usuario.setEmail("user@example.com");
            usuario.setSenha("senha123");
    
            when(usuarioRepository.save(usuario)).thenReturn(usuario);
    
            Usuario usuarioSalvo = usuarioService.save(usuario);
            assertNotNull(usuarioSalvo);
            assertEquals(usuario.getEmail(), usuarioSalvo.getEmail());
        }
    }

  9. Executando a Aplicação e Testes

    Utilize o Maven para compilar e executar a aplicação. Após iniciar a aplicação, use ferramentas como Postman ou cURL para testar os endpoints de registro e login.

    commands
    # Compilar e executar a aplicação
    mvn spring-boot:run
    # Executar os testes
    mvn test

    curl_examples
    # Registar um novo usuário
    curl -X POST -H "Content-Type: application/json" -d '{"email":"user@example.com", "senha":"senha123"}' http://localhost:8080/api/auth/register
    # Fazer login
    curl -X POST -H "Content-Type: application/json" -d '{"email":"user@example.com", "senha":"senha123"}' http://localhost:8080/api/auth/login

Conclusão

Neste tutorial, você aprendeu a implementar um sistema de autenticação em uma aplicação web utilizando o Spring Boot, JWT e OAuth. Discutimos desde a configuração do projeto até as implementações necessárias para suportar registro de usuários e autenticação com tokens. Com esses conhecimentos, você pode melhorar a segurança de suas aplicações, garantindo acesso restrito e autenticado, o que é essencial no ambiente atual de ameaças cibernéticas. Continue a explorar e expandir suas implementações para criar soluções ainda mais robustas.

Hashtags

#SpringBoot #JWT #OAuth #Autenticação #SegurançaWeb #DesenvolvimentoDeSoftware