Para criar o controle de acesso, todas as requisições devem enviar o token jwt e verificar a sua validade. Para que isso seja feito de maneira que não seja necessário repetir código no controller, é criado uma classe que é responsável por essa validação. Desta forma, a requisição é interceptada antes de chegar ao controller. Este interceptador é o Handler Interceptor do Spring, que funciona como um Filter da especificação Servlet.

Untitled

A classe que representa o Filter é anotada com @Component, essa anotação é utilizada para que o Spring carregue uma classe genérica. Esta classe também deve herdar da classe OncePerRequestFilter do Spring e implementar o método doFilter().

Para que a requisição seja repassada para o próximo filtro, é necessário utilizar o método doFilter() do objeto FilterChain.

O Token é enviando no cabeçalho da requisição, por ser uma informação de configuração. Este cabeçalho é chamado de Authorization.

Para validar o Token:

public String getSubject(String tokenJWT){
    try {
        Algorithm 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", exception);
    }
}

Autenticação do usuário

@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 = usuarioRepository.findByLogin(subject);

						//força a autenticação
            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;
    }
@Bean //devolver um objeto para o Spring
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
    return http.csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeHttpRequests()
            .requestMatchers(HttpMethod.POST, "/login").permitAll() //desabilita filtro para endpoint de login
            .anyRequest().authenticated() //habilita para todos os outros
            .and().addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
    //desabilita proteçao contra ataques Cross-Site Request Forgery -> Token já faz isso
    //desabilita Statefull
}

O que foi aprendido?