1
resposta

[Dúvida] Integração com o Front-end

Boa noite a todos. Tudo bem?

Por gentileza, poderia me auxiliar? Estou criando um front-end utilizando o JS para ser consumido a API, no entanto, ao mandar a requisição POST para realizar o Login consta essa mensagem abaixo:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Segue função utilizada para fazer a requisição e a classe SecurityConfig e SecurityFilter:

function Login() {
  const login = {
    login: document.getElementById("login").value,
    senha: document.getElementById("senha").value  
  };

  const param = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(login)
  };

  fetch('http://localhost:8080/login', param)
  .then(response => response.json()) // Converte a resposta em JSON
    .then(data => {
      console.log('Login efetuado com sucesso!', data);
    })
    .catch(error => {
      console.error("Ocorreu um erro ao executar a rotina: " + error);
    });
  }

SecurityConfig:

@Configuration
@EnableWebSecurity
@EnableWebMvc
public class SecurityConfig implements WebMvcConfigurer {

    @Autowired 
    private SecurityFilter securityFilter;
    
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {

        CorsConfiguration configuration = new CorsConfiguration().applyPermitDefaultValues();
        configuration.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "DELETE", "OPTIONS"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
    

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return 
                http.csrf(csrf -> csrf.disable())
                .cors(Customizer.withDefaults()) // incluir essa configuração para o Cors
                .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(req -> {
                    req.requestMatchers(HttpMethod.POST,"/login").permitAll();
                    req.anyRequest().authenticated();}).addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class).build();
    }
    
    
    

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration conf) throws Exception {
        return conf.getAuthenticationManager();
    }

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

}

SecurityFilter:

@Component // estou informando que essa classe é uma classe generica
public class SecurityFilter extends OncePerRequestFilter {

    @Autowired
    private TokenService token;
    
    @Autowired
    private UsuarioRepository repo;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type");
        
        var tokenJWT = recuperarToken(request);

        if (tokenJWT != null) {
            var subject = token.getSubject(tokenJWT); // busco o subject onde consta o usuário 
            var usuario = repo.findByLogin(subject); // verifico se o usuario existe no banco
            var authentication = new UsernamePasswordAuthenticationToken(usuario,null,usuario.getAuthorities()); // cria o DTO do Spring com base nas informações buscadas 
            
            
            SecurityContextHolder.getContext().setAuthentication(authentication); // realizado a autenticação 
        
        }

        filterChain.doFilter(request, response); // utiliza o filterChain para ser liberado o proximo filtro de
                                                    // requisicao.

    }

    private String recuperarToken(HttpServletRequest request) {
        var authorizationHeader = request.getHeader("Authorization");

        if (authorizationHeader != null) {

            return authorizationHeader.replace("Bearer ", "");
        }

        return null;
    }

}
1 resposta

Olá João, tudo bem?

Pelo erro que você compartilhou, parece que a resposta da sua API não é um JSON válido, mas sim um token JWT. Isso ocorre porque a linha response.json() está tentando converter a resposta em JSON, mas o que você está recebendo é um token.

Para resolver isso, você pode verificar o status da resposta antes de tentar convertê-la em JSON. Caso a resposta seja um token, você pode tratá-la de forma diferente. Veja como você pode ajustar o código:

function Login() {
  const login = {
    login: document.getElementById("login").value,
    senha: document.getElementById("senha").value  
  };

  const param = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(login)
  };

  fetch('http://localhost:8080/login', param)
    .then(response => {
      if (!response.ok) {
        throw new Error('Erro ao fazer login');
      }
      return response.text(); // Use text() para pegar a resposta como string
    })
    .then(token => {
      console.log('Login efetuado com sucesso!', token);
      // Armazene o token para uso futuro, por exemplo, no localStorage
      // localStorage.setItem('token', token);
    })
    .catch(error => {
      console.error("Ocorreu um erro ao executar a rotina: " + error);
    });
}

Nesse ajuste, response.text() é usado para capturar a resposta como texto, que é o que você espera quando recebe um token JWT.

Espero ter ajudado e bons estudos!