Solucionado (ver solução)
Solucionado
(ver solução)
12
respostas

403 Forbidden - apenas na requisição de Consulta

Implementei os códigos para agendamento de consultas. O projeto rodou. Porém, no Insomnia, apenas a requisição "Agendar Consulta" é rejeitada (403 Forbiden), as outras funcionam normalmente.

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

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

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

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

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

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

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

Garanta sua matrícula hoje e ganhe + 2 meses grátis

Continue sua jornada tech com ainda mais tempo para aprender e evoluir

Quero aproveitar agora
12 respostas

Oi!

No seu controller tem um system.out imprimindo os dados da requisição. Esse texto apareceu no console?

Bom dia professor.

No console não apareceu o texto da requisição. Apenas os system.out do filtro, que eu mantive do curso anterior.

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

Ok. Manda aqui suas classes SecurityFilter e SecurityConfigurations

@Component
public class SecurityFilter extends OncePerRequestFilter{

    @Autowired
    private TokenService tokenService;

    //para injetar o repository neste filtro, para permitir uma consulta no BD
    @Autowired
    private UsuarioRepository repository;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException
    {
        //varíável que recebe o token a partir de um método que extrai o token
        var tokenJWT = recuperarToken(request);
        //System.out.println(tokenJWT);
        System.out.println("FILTRO SENDO CHAMADO!!!!");

        /*
         * Valida, se existir, o token e recupera o seu subject
         */
        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);

            System.out.println("LOGADO NA REQUISIÇÃO");
        }

        /*
         * para verificar se recuperou o subject do token
         */
        // System.out.println(subject);

        /*
         * para chamar o próximo filtro, encaminhando o request e o response
         */
        filterChain.doFilter(request, response);
    }

    private String recuperarToken(HttpServletRequest request) {
        var authorizationHeader = request.getHeader("Authorization");
        //se existe o cabeçalho
        if (authorizationHeader!=null){
            return authorizationHeader.replace("Bearer ", "");
        }
        return null;
    }
    
}

/*
 * como é uma classe de configurações, usamos a anotação @Configuration
 * dessa forma o Spring irá carregar essa classe no projeto
 */
@Configuration
/*
 * como vamos personalizar o processo de autenticação e de autorização
 * precisamos da anotação @EnableWebSecurity
 */
@EnableWebSecurity
public class SecurityConfiguration {

    //para injetar a classe SecurityFilter
    @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.anyRequest().authenticated();
            })
        .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
        .build();
    }


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

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

@Configuration /*

  • como vamos personalizar o processo de autenticação e de autorização

  • precisamos da anotação @EnableWebSecurity */ @EnableWebSecurity public class SecurityConfiguration {

    //para injetar a classe SecurityFilter @Autowired private SecurityFilter securityFilter;

    /*

    • para que o spring leia o retorno desse método automaticamente
    • devemos inserir a anotação
    • @Bean
    • Essa anotação expõem o retorno deste método para o Spring */ @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.anyRequest().authenticated(); }) .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class) .build(); }

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

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

}

Acho que deu problema no envio dessas classes.

Deve ser algum outro erro que está acontecendo, mas o Spring Security captura e devolve erro 403.

Altera a sua classe de tratamento de erros para tratar mais erros, conforme essa atividade: https://cursos.alura.com.br/course/spring-boot-aplique-boas-praticas-proteja-api-rest/task/125341

Dispare a requisição e veja no console e no retorno se mudou o erro.

Adicionei os outros métodos para tratamento de erros, mas não houve mudança no retorno.

@RestControllerAdvice public class TratadorDeErros{ //método para lidar com a Exception: EntityNotFoundException @ExceptionHandler(EntityNotFoundException.class) public ResponseEntity tratarErro404(){ return ResponseEntity.notFound().build(); //o build é para que ele crie o objeto ResponseEntity }

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity tratarErro400(MethodArgumentNotValidException ex){
    var erros = ex.getFieldErrors();
    return ResponseEntity.badRequest().body(erros.stream().map(DadosErroValidacao::new).toList());
}

 @ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity tratarErro400(HttpMessageNotReadableException ex) {
    return ResponseEntity.badRequest().body(ex.getMessage());
}

 @ExceptionHandler(BadCredentialsException.class)
public ResponseEntity tratarErroBadCredentials() {
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Credenciais inválidas");
}

@ExceptionHandler(AuthenticationException.class)
public ResponseEntity tratarErroAuthentication() {
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Falha na autenticação");
}

@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity tratarErroAcessoNegado() {
    return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Acesso negado");
}

@ExceptionHandler(Exception.class)
public ResponseEntity tratarErro500(Exception ex) {
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Erro: " +ex.getLocalizedMessage());
}

//DTO que retorna apenas os campos que desejamos, em caso de erro de validação
private record DadosErroValidacao(String campo, String mensagem){

    public DadosErroValidacao(FieldError erro){

        //chama o construtor padrão do DTO, passando o campo e a mensagem de erro
        this(erro.getField(), erro.getDefaultMessage());
    } 
}

}

Consegue compartilhar o teu projeto?

Professor, veja se consegue acessar:

https://github.com/benedditto/AgendamentoConsulta/tree/main/MedVoll

solução!

No seu projeto, no pacote controller. você criou uma anotação chamada @RestController. Apague esse arquivo e no ConsultaController importe essa anotação do Spring.

Opa, deu certo professor. Muito obrigado.