6
respostas

Erro 403 Forbidden no tentar gerar um token em /login

@RestController
@RequestMapping("/login")
public class AtenticacaoController {

    @Autowired
    private AuthenticationManager manager;
    @Autowired
    private TokenService tokenService;

    @PostMapping
    public ResponseEntity efetuarLogin (@RequestBody @Valid DadosAutenticacao dados) {
       var authenticationToken = new UsernamePasswordAuthenticationToken(dados.login(), dados.senha());
       var authentication=  manager.authenticate(authenticationToken);
       var tokenJWT = tokenService.gerarToken((Usuario) authentication.getPrincipal());
       return ResponseEntity.ok(new tokenDadosTokenJWT(tokenJWT));

    }

}
@Configuration
@EnableWebSecurity
public class SecurityConfigurations {

    @Autowired
    private SecurityFilter securityFilter;
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        return http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeHttpRequests()
                .requestMatchers(HttpMethod.POST, "/login").permitAll()
                .anyRequest().authenticated()
                .and().addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration)throws Exception{
        return configuration.getAuthenticationManager();
    }
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
@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 ","");
        }
        return null;
    }
}
@Service
public class TokenService {

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

    public String gerarToken(Usuario usuario) {
        try {
            var algoritmo = Algorithm.HMAC256(secret);
            return JWT.create()
                    .withIssuer("API Voll.med")
                    .withSubject(usuario.getLogin())
                    .withExpiresAt(dataExpiracao())
                    .sign(algoritmo);
        } catch (JWTCreationException exception) {
            throw new RuntimeException("erro ao gerar token JWT", exception);
        }
    }

    public String getSubject(String tokenJWT){
        try {
            var algoritmo = Algorithm.HMAC256(secret);
           return JWT.require(algoritmo)
                   .withIssuer("API voll.med")
                   .build()
                   .verify(tokenJWT)
                   .getSubject();
        } catch (JWTVerificationException exception){
            throw new RuntimeException("Token JWT inválido ou expirado");

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

}

Exception: java.lang.RuntimeException: Token JWT inválido ou expirado at med.voll.api.infra.security.TokenService.getSubject(TokenService.java:46) ~[classes/:na] at med.voll.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:33) ~[classes/:na]

6 respostas

Olá Geraldo!

Vi no seu código que o issuer está diferente nos métodos gerarToken e getSubject. A letra V está maiúscula em um método e minúscula no outro, sendo que isso pode invalidar o token.

Mesmo com as duas letras V maiúsculas, a exception ainda persiste!

Altera o catch do método getSubject para ficar assim:

} catch (JWTVerificationException exception) {
    System.out.println("TOKEN: " +tokenJWT);
    exception.printStackTrace();
    throw new RuntimeException("Token JWT inválido ou expirado");
}

E posta aqui a saída do console.

Hibernate: 
    select
        u1_0.id,
        u1_0.login,
        u1_0.senha 
    from
        usuarios u1_0 
    where
        u1_0.login=?

Essa é a saída no console.

Coloca um try/catch no controller então, apra ver a exception que de fato está ocorrendo:

try {
    var authenticationToken = new UsernamePasswordAuthenticationToken(autenticacao.login(), autenticacao.senha());
    var authentication = authenticationManager.authenticate(authenticationToken);
} catch (Exception e) {
    e.printStackTrace();
}

Geraldo,

Verifique se vocês esta mandando o token na requisição para o /login.

Pois nessa requisição voce vai obter um novo token e como tem token ele vai cair no metodo de verificar o token e pode da essa exceção.