1
resposta

[Dúvida] Como resgatar o header Authorization da requisição HTTP com o Spring?

Bom, em meu projeto estou realizando uma função de criação, usando POST, e estou usando a autenticação com tokens JWT. Até o momento consegui fazer o navegador guardar o token, porém ao enviá-lo no header, como será possível ver nos códigos abaixo, para fazer a autenticação, o Spring não reconhece esse parâmetro, retornando null. Vale dizer que estou recolhendo o token em um Filter.

Código JS:

// USER REGISTER FUNCTION //
const formConsumerRegister = document.querySelector("#consumer-register-form");
const message = document.querySelector("#alert");

formConsumerRegister.addEventListener("submit", (event) => {
    event.preventDefault()

    var formData =  new FormData(formConsumerRegister);
    var data = Object.fromEntries(formData);
    var jsonData = JSON.stringify(data);

    fetch("http://localhost:8080/consumer", {
        mode: "cors",
        method: "POST",
        headers: {
            'Authorization': `Bearer ${localStorage.getItem("token")}`,
            'Access-Control-Allow-Origin': 'http://localhost:8080',
            'Access-Control-Allow-Credentials': 'true',
            'Content-Type': 'application/json'
        },
        body: jsonData
    })
    .then(response => {
        if(!response.ok){
            message.innerHTML = "Error...";
            message.style.color = "#FF0000";

            throw new Error("HTTP Status " + response.status);
        }
        
        return response
    })
    .then(data => {
        message.innerHTML = "Consumer created!";
        message.style.color = "#00FF00";
        window.location = "dashboardPage.html";
    })
    .catch(err => {
        console.log(err)
        message.innerHTML = "Auth Error...";
        message.style.color = "#FF0000";
    })
})

Filter no Spring:

@Component
public class SecurityFilter extends OncePerRequestFilter {

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UserRepository userRepository;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        var tokenJWT = getToken(request);

        if(tokenJWT != null){
            var subject = tokenService.getSubject(tokenJWT);
            System.out.println(subject);
            var user = userRepository.findByUser(subject);

            var authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());

            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }

    private String getToken(HttpServletRequest request) {
        var authHeader = request.getHeader("Authorization");

        System.out.println(authHeader); // printando null aqui

        if(authHeader != null){
            return authHeader.replace("Bearer ", "");
        }

        return null;
    }
}

Arquivo de configurações do Spring:

@Configuration
@EnableWebSecurity
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("/login").permitAll();
                    req.requestMatchers("/login/verify").permitAll();
                    req.anyRequest().authenticated();
                })
                .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)

                .build();
    }

    @Bean
    public AuthenticationManager authManager(AuthenticationConfiguration config) throws Exception{
        return config.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

Abaixo tambem vou deixar o resultado recebido no console do navegador: Insira aqui a descrição dessa imagem para ajudar na acessibilidade

1 resposta

Oi

O problema que você está enfrentando parece estar relacionado a duas questões: CORS (Cross-Origin Resource Sharing) e a passagem do token JWT para o servidor Spring. Vamos abordar essas questões separadamente.

CORS (Cross-Origin Resource Sharing)

O erro menciona que a política CORS está bloqueando a solicitação devido à falta do cabeçalho 'Access-Control-Allow-Origin'. Isso significa que sua aplicação front-end (executada em http://127.0.0.1:5500) está tentando fazer uma solicitação para o servidor de back-end (executado em http://localhost:8080), e o servidor de back-end não está configurado para permitir solicitações de origens diferentes por padrão.

Para resolver o problema de CORS, você deve configurar o servidor Spring para permitir solicitações de origens diferentes. Você pode fazer isso no código de configuração do Spring Security. Modifique sua classe SecurityConfigurations da seguinte maneira:

@Configuration
@EnableWebSecurity
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("/login").permitAll();
                    req.requestMatchers("/login/verify").permitAll();
                    req.anyRequest().authenticated();
                })
                .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .cors() // Adicione esta linha para configurar o CORS
                .and()
                .build();
    }

    // ... outras configurações
}

Em seguida, configure o CORS permitindo que a origem do seu aplicativo front-end acesse o servidor Spring. Você pode fazer isso em uma classe de configuração separada. Aqui está um exemplo:

@Configuration
public class CorsConfig {

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://127.0.0.1:5500")); // Adicione a origem do seu aplicativo front-end
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
        configuration.setAllowCredentials(true);
        configuration.addAllowedHeader("Authorization");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

Passagem do Token JWT

No código JavaScript, você está configurando o cabeçalho 'Authorization' para enviar o token JWT da seguinte maneira:

headers: {
    'Authorization': `Bearer ${localStorage.getItem("token")}`,
    // ...
}

Certifique-se de que localStorage.getItem("token") esteja realmente retornando o token JWT correto. Você pode verificar isso imprimindo o valor no console antes de enviar a solicitação:

console.log(localStorage.getItem("token"));

Verifique se o token está correto e se o valor está sendo definido no localStorage corretamente.

Certifique-se de que o token esteja no formato adequado, começando com "Bearer" seguido por um espaço e, em seguida, o token JWT.

Se o token JWT estiver sendo configurado corretamente no cabeçalho 'Authorization', o Spring deverá ser capaz de reconhecê-lo no filtro de segurança.

Certificando-se de que a política CORS esteja configurada corretamente e que o token JWT seja passado corretamente no cabeçalho 'Authorization', você deve ser capaz de autenticar as solicitações no seu aplicativo Spring com sucesso.