📚 Pré-requisitos Teóricos: este projeto aplica conceitos ensinados em Especialização em Backend com Java e Spring Boot. Recomendado revisar antes de começar.
Bem-vindo ao Módulo 6 do nosso plano de expansão! Agora que nossa aplicação está testada e funcionando, vamos dar o próximo passo rumo ao nível profissional: Segurança.
Neste guia, vamos aprender a proteger nossa API da Biblioteca de Jogos usando o framework Spring Security e tokens JWT (JSON Web Token) para autenticação sem estado (stateless).
pom.xmlPara trabalhar com segurança e JWT, precisamos adicionar o starter do Spring Security e uma biblioteca para manipulação de tokens JWT. Vamos usar a biblioteca jjwt, que é muito robusta e popular.
Abra o arquivo pom.xml e adicione as seguintes dependências:
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Dependências para o JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
Por padrão, ao adicionar o Spring Security, ele bloqueia todas as rotas da aplicação e gera uma senha aleatória no console. Vamos criar uma classe de configuração para dizer ao Spring como queremos que a segurança funcione.
Crie a classe SecurityConfig.java no pacote br.com.bibliotecajogos.config:
package br.com.bibliotecajogos.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // Desabilita CSRF (comum em APIs REST)
// Configura a sessão como STATELESS (sem estado), necessária para JWT
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
// Permite que qualquer pessoa liste os jogos
.requestMatchers("/jogos").permitAll()
// Apenas usuários logados com a role ADMIN podem criar ou excluir jogos
.requestMatchers("/jogos/novo", "/jogos/excluir/**").hasRole("ADMIN")
// Qualquer outra requisição exige autenticação
.anyRequest().authenticated()
)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
// Define o codificador de senhas que usaremos no banco de dados
return new BCryptPasswordEncoder();
}
}
O JSON Web Token é uma string longa dividida em 3 partes separadas por pontos (.):
Fluxo de Funcionamento:
Authorization: Bearer <TOKEN>.@EnableWebSecurity: Diz ao Spring para desativar a segurança padrão e usar as regras que definimos nesta classe.csrf().disable(): O CSRF protege contra ataques em aplicações que usam cookies/sessões. Como usaremos JWT (stateless), podemos desabilitá-lo.SessionCreationPolicy.STATELESS: Garante que o Spring não criará sessões HTTP no servidor. Cada requisição deve ser independente e trazer seu próprio token.hasRole("ADMIN"): É aqui que a mágica da Autorização acontece. O Spring verifica se o usuário autenticado possui essa permissão antes de liberar o acesso à rota.Pesquise sobre a diferença entre .hasRole("ADMIN") e .hasAuthority("ADMIN") no Spring Security. Como isso muda a forma como guardamos as permissões no banco de dados?
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/jogos").permitAll()
.requestMatchers("/jogos/novo", "/jogos/excluir/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
cd catalogo_projetos/javaweb_jogos_guia_seguranca/web-spring
./mvnw spring-boot:run
No Windows (PowerShell):
cd catalogo_projetos\javaweb_jogos_guia_seguranca\web-spring
.\mvnw.cmd spring-boot:run
# 1. Consulta pública (deve retornar 200 OK)
> 📁 **Código deste projeto:** `web-spring/` (os caminhos citados abaixo são relativos à subpasta).
<p align="center"><img src="assets/arquitetura_jogos_guia_seguranca.svg" alt="Diagrama de arquitetura do projeto" style="max-width: 100%; height: auto;"></p>
curl -i http://localhost:8080/jogos
# 2. Tentativa de cadastro sem token (deve retornar 401 ou 403)
curl -i -X POST http://localhost:8080/jogos/novo