Introdução
No desenvolvimento de aplicações web modernas, a criação de APIs RESTful é fundamental para a comunicação entre diferentes sistemas. Este tutorial detalha como usar Java com o Spring Boot para construir uma aplicação RESTful que não apenas é escalável, mas também segura, utilizando a autenticação JSON Web Token (JWT). O Spring Boot simplifica o processo de configuração e desenvolvimento, permitindo que os desenvolvedores se concentrem na lógica de aplicação. Neste guia, vamos explorar cada etapa, desde a configuração do projeto até a implementação de funcionalidades complexas, garantindo que você aprenda como criar um serviço RESTful robusto e seguro.
Etapas
Configuração do Ambiente de Desenvolvimento
Primeiramente, você precisa assegurar que o JDK e o Maven estejam instalados. Verifique isso executando `java -version` e `mvn -version` no terminal. Se não estiverem instalados, siga as instruções da documentação oficial para fazer a instalação.
commands# Verificando as versões instaladas
java -version
mvn -versionCriação do Projeto Spring Boot
Utilize o Spring Initializr (https://start.spring.io/) para gerar um novo projeto Spring Boot. Escolha as configurações: **Project**: Maven, **Language**: Java, **Spring Boot**: última versão estável, **Packaging**: Jar, **Java**: 11 ou superior. Adicione as dependências ‘Spring Web’, ‘Spring Data JPA’, ‘Spring Security’, e ‘jjwt’. Baixe e descompacte o projeto em sua máquina.
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>api-jwt</artifactId> <version>0.0.1-SNAPSHOT</version> <name>api-jwt</name> <description>API RESTful com Spring Boot e JWT</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-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</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>
Configuração do Banco de Dados H2
Edite o arquivo `application.properties` para definir as propriedades do banco de dados H2 e habilitar o console web para visualização dos dados.
application.propertiesspring.h2.console.enabled=true spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=update
Configuração do Client JWT
Implemente uma classe utilitária `JwtUtil` que será responsável pela criação e validação do token JWT.
JwtUtil.javapackage com.example.apijwt.util; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.stereotype.Component; import java.util.Date; import java.util.HashMap; import java.util.Map; @Component public class JwtUtil { private String secret = "minha-chave-secreta"; // Mantenha isso seguro! private long expirationTime = 1000 * 60 * 60; // 1 hora public String gerarToken(String username) { Map<String, Object> claims = new HashMap<>(); return criarToken(claims, username); } private String criarToken(Map<String, Object> claims, String subject) { return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + expirationTime)) .signWith(SignatureAlgorithm.HS256, secret).compact(); } public boolean validarToken(String token, String username) { final String usernameDoToken = obterUsernameDoToken(token); return (usernameDoToken.equals(username) && !isTokenExpirado(token)); } private String obterUsernameDoToken(String token) { return obterClaims(token).getSubject(); } private Claims obterClaims(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } private boolean isTokenExpirado(String token) { return obterClaims(token).getExpiration().before(new Date()); } }
Implementação do Controlador de Autenticação
Crie um controlador `AuthController` que gerencia o login e a geração do token JWT.
AuthController.javapackage com.example.apijwt.controller; import com.example.apijwt.util.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/auth") public class AuthController { @Autowired private JwtUtil jwtUtil; @PostMapping("/login") public String login(@RequestBody Map<String, String> usuario) { // Aqui você pode adicionar validação do usuário return jwtUtil.gerarToken(usuario.get("username")); } }
Criação da Entidade e Repositório de Usuário
Implemente a classe `Usuario`, e o repositório `UsuarioRepository` para gerenciamento dos dados do usuário.
Usuario.javapackage com.example.apijwt.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 username; @Column(nullable = false) private String password; // Getters e Setters }
UsuarioRepository.javapackage com.example.apijwt.repository; import com.example.apijwt.model.Usuario; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface UsuarioRepository extends JpaRepository<Usuario, Long> { Usuario findByUsername(String username); }
Configuração do Spring Security
Implemente a configuração de segurança para proteger as rotas da API e permitir acesso somente aos usuários autenticados.
SecurityConfig.javapackage com.example.apijwt.config; import com.example.apijwt.filter.JwtRequestFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtRequestFilter jwtRequestFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/auth/login").permitAll() .anyRequest().authenticated() .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { // Configurações de autenticação aqui se necessário } @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
Implementação do Filtro de Requisição JWT
Crie um filtro `JwtRequestFilter` que intercepta as requisições para validar o token JWT.
JwtRequestFilter.javapackage com.example.apijwt.filter; import com.example.apijwt.util.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class JwtRequestFilter extends OncePerRequestFilter { @Autowired private JwtUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { final String authorizationHeader = request.getHeader("Authorization"); String username = null; String jwt = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); username = jwtUtil.obterUsernameDoToken(jwt); } if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { // Autentique o usuário aqui - Implementa sua lógica } chain.doFilter(request, response); } }
Executando a Aplicação e Testes
Use o Maven para compilar e executar a aplicação. Teste os endpoints utilizando ferramentas como Postman ou cURL.
commands# Compilar e executar a aplicação
mvn spring-boot:run
# Testes com cURL
curl -X POST -H "Content-Type: application/json" -d '{"username":"user", "password":"password"}' http://localhost:8080/api/auth/login
curl -X GET -H "Authorization: Bearer <token>" http://localhost:8080/api/produtos
Conclusão
Neste tutorial, você explorou como desenvolver uma aplicação RESTful escalável e segura usando Java e Spring Boot com autenticação JWT. Foi abordado desde a configuração inicial do projeto até a implementação de controle de acesso e segurança. Você agora possui a base necessária para expandir essa aplicação, implementando funcionalidades adicionais, integração com bancos de dados persistentes e refinando a segurança do seu sistema. Essa abordagem não só melhora a segurança das suas aplicações, mas também prepara você para os desafios do mercado atual.