7
respostas

[Dúvida] Dúvida sobre versão 3.2.3 do Spring Boot

Olá Pessoal alguém sabe me dizer como ficaria esse código para a versão 3.2.3 do Spring Boot.

@Configuration
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfigurations {
    @Autowired
    private SecurityFilter securityFilter;
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
        return http.csrf(csrf -> csrf.disable())
                .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(req -> {
                    req.requestMatchers(HttpMethod.POST,"/login").permitAll();
                    req.requestMatchers(HttpMethod.GET,"/produto").hasRole("USER");
                    req.requestMatchers(HttpMethod.POST,"/produto").hasRole("USER");
                    req.anyRequest().authenticated();

                })
                .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

Mesmo com essa alteração, o filtro que esta sendo chamado ainda é o securityFilterChain, isso significa que todas as minhas requisições estão sendo broqueadas, alguém tem alguma dica pra resolver esse dilema?

7 respostas

Oi!

O código está correto. Manda aqui o código da sua classe SecurityFilter

Olá Rodrigo estou tendo esse erro ao enviar requisições;

"java.lang.RuntimeException: Token não valido ou EXPIRADO at com.estoque_propriedade_rural.api.infra.security.TokenService.getSubject(TokenService.java:44) ~[classes/:na] at com.estoque_propriedade_rural.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:29) ~[classes/:na] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.4.jar:6.1.4] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2] at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) ~[spring-web-6.1.4.jar:6.1.4] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.4.jar:6.1.4]"

O código da classe SecurityFilter esta assim enquanto acontece o erro.

package com.estoque_propriedade_rural.api.infra.security;

import com.estoque_propriedade_rural.api.domain.usuario.UsuarioRepository;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
public class SecurityFilter extends OncePerRequestFilter {
    @Autowired
    private TokenService tokenService;
   @Autowired
    private UsuarioRepository repository;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {


       var tokenJWT = recuperarToken(request);

        if(tokenJWT != null) {
            var subject = tokenService.getSubject(tokenJWT);
            var usuario = repository.findByLogin(subject);

            var authentication = new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }
    private String recuperarToken(HttpServletRequest request) {
        var authorizationHeader = request.getHeader("Authorization");
        if (authorizationHeader != null) {
            return authorizationHeader.replace("Bearer", "").trim();
       }
        return null;
    }
}

O token esta sendo gerado, esta entrando no if, mas esta retornando essa mensagem de token invalido mesmo o token não estando expirado.

Pelo erro está chegando um token inválido ou expirado na requisição. Coloca um System.out para imprimir o token que está chegando na API:

var tokenJWT = recuperarToken(request);

System.out.println("TOKEN RECEBIDO:" +tokenJWT);

Fiz como você sugeriu e foi retornado a String com o token no console juntamente com o erro:

TOKEN RECEBIDO: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcGkiLCJzdWIiOiJjbGF1ZGluZWlhbHZlcyIsImV4cCI6MTcxMzgzNDAwMn0.Ow1yeyX42TFJwJR11FNDsWENvVKgF0FGiu3AChgU2Wc" 2024-04-22T21:24:11.538-03:00 ERROR 4992 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

java.lang.RuntimeException: Token não valido ou EXPIRADO at com.estoque_propriedade_rural.api.infra.security.TokenService.getSubject(TokenService.java:43) ~[classes/:na] at com.estoque_propriedade_rural.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:31) ~[classes/:na] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.4.jar:6.1.4] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.2.jar:6.2.2]

java.lang.RuntimeException: Token não valido ou EXPIRADO.

O token está certinho. Manda aqui o código da sua classe TokenService

Aqui esta a minha classe TokenService:

package com.estoque_propriedade_rural.api.infra.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.estoque_propriedade_rural.api.domain.usuario.Usuario;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

@Service
public class TokenService {
    @Value("${api.security.token.secret}")
    private String secret;

    private static final String ISSUER = "api";
    public String gerarToken(Usuario usuario) {
        try {
            var Algoritmo = Algorithm.HMAC256(secret);
            return JWT.create()
                    .withIssuer(ISSUER)
                    .withSubject(usuario.getLogin())
                    .withExpiresAt(dataExpiracao())
                    .sign(Algoritmo);
        } catch (JWTCreationException exception) {
            throw new RuntimeException("Erro ao gerar token jwt");
        }
    }

    public String getSubject(String tokenJWT) {
        try {
            var Algoritmo = Algorithm.HMAC256(secret);
            return JWT.require(Algoritmo)
                    .withIssuer(ISSUER)
                    .build()
                    .verify(tokenJWT)
                    .getSubject();
        } catch (JWTVerificationException exception) {
            throw new RuntimeException("Token não valido ou EXPIRADO ");
        }

    }
    private Instant dataExpiracao() {
        return LocalDateTime.now().plusHours(1).toInstant(ZoneOffset.of("-03:00"));
    }
}

Fiz mais uns testes e o token não caiu nesse System.out.println( "TOKEN ENTOU NO IF " + tokenJWT); que esta dentro do if.

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {


       var tokenJWT = recuperarToken(request);

        System.out.println("TOKEN RECEBIDO: " + tokenJWT);

        if(tokenJWT != null) {
            var subject = tokenService.getSubject(tokenJWT);
            System.out.println( "TOKEN ENTROU NO IF " + tokenJWT);
            var usuario = repository.findByLogin(subject);

            var authentication = new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }

Estou com o mesmo erro.:

Chamando Filter

Recebeu token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhbmEuc291emFAdm9sbC5tZWQiLCJpc3MiOiJBUEkgdm9sbC5tZWQiLCJleHAiOjE3MTM5NzQyNTN9.AFgekcJsNgL8-QHT3zfF1efQW-LMxn4g7mupCcwU56Y

2024-04-24T10:58:08.360-03:00 ERROR 23760 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

java.lang.RuntimeException: Token JWT inválido ou expirado! at med.voll.api.infra.secutity.TokenService.getSubject(TokenService.java:43) ~[classes/:na] at med.voll.api.infra.secutity.SecurityFilter.doFilterInternal(SecurityFilter.java:32) ~[classes/:na] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5]