Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
10
respostas

[Bug] Erro 403

Esta dando erro 403 na hora de fazer a consulta, na hora de cadastrar ou listar o token funciona mas no, metode de consulta nao esta funcionando assim estao o crontroller, DTOs e JPA`package med.absolut.api.controller;

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;

import jakarta.transaction.Transactional; import jakarta.validation.Valid; import med.absolut.api.consulta.ConsultaRepository; import med.absolut.api.consulta.DadosAgendamento; import med.absolut.api.consulta.DadosDetalhamentoConsulta;

@RestController @RequestMapping("/consultas") public class ConsultaController {

@Autowired
private ConsultaRepository repository;

@PostMapping
@Transactional
public ResponseEntity agendar(@RequestBody @Valid DadosAgendamento dados) {
    return ResponseEntity.ok(new DadosDetalhamentoConsulta(null, null, null, null));
}

} `

package med.absolut.api.consulta;

import java.time.LocalDateTime;

public record DadosDetalhamentoConsulta(Long id, Long idMedico, Long idPaciente, LocalDateTime data) {

}
package med.absolut.api.consulta;

import java.time.LocalDateTime;

import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.NotNull;

public record DadosAgendamento(
        
        Long idMedicos,
        
        @NotNull
        Long idPacientes,
        
        @NotNull
        @Future
        LocalDateTime data
        
        ) {

}
package med.absolut.api.consulta;

import java.time.LocalDateTime;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import med.absolut.api.medico.Medico;
import med.absolut.api.paciente.Paciente;

@Table(name = "consultas")
@Entity(name = "Consulta")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class Consulta {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "medicos_id")
    private Medico medico;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pacientes_id")
    private Paciente paciente;
    
    private LocalDateTime data;
    
    
}

package med.absolut.api.consulta;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ConsultaRepository extends JpaRepository<Consulta, Long>{

}
10 respostas

Oi!

Como você está disparando a requisição? Manda aqui um print do insomnia

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

No seu controller o método agendar recebe como parâmetro um objeto do tipo DadosAgendamento, então o json enviado na requisição deve bater com os atributos desse objeto.

No caso não está batendo, pq no seu json o campo foi como idMedico, mas no DadosAgendamento o atributo se chama idMedicos (no plural).

Ajuste o código para que os atributos tenham o mesmo nome que os campos do json.

Eu arrumei porem continuou com o erro 403

Veja no console do IntelliJ se apareceu alguma mensagem. E mande aqui tambem o codigo das suas classes SecurityConfigurations e SecurityFilter e TokenService


@Configuration
@EnableWebSecurity
public class SecurityConfiguaration{

    @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();
                    })
                .build();
    }

    @Bean
    public AuthenticationManager authenticate(AuthenticationConfiguration configuration) throws Exception{
 
        return configuration.getAuthenticationManager();
    }
    
    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }
}
@Service
public class TokenService {

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

    public String geraToken(Usuario usuario ) {
        
    try {
        var algorithm = Algorithm.HMAC256(secret);
        
        return JWT.create()
            .withIssuer("Api Absolut.med")
            .withSubject(usuario.getSenha())
            .withExpiresAt(dadosTempo())
            .sign(algorithm);
        
    } catch (JWTCreationException exception){
        throw new RuntimeException("Erro ao gerar o token");
    }
  }

    public String getSubject(String tokenJWT) {
        try {
              var algorithm = Algorithm.HMAC256(secret);		   
              return JWT.require(algorithm)
                .withIssuer("Api Absolut.med")
                .build()
                .verify(tokenJWT)
                .getSubject();
                
          
        } catch (JWTVerificationException exception){
            throw new RuntimeException("Token invalido ou expirado");
        }
    }
    
    private Instant dadosTempo() {
        return LocalDateTime.now().plusHours(2).toInstant(ZoneOffset.of("-03:00"));
    }
}
@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;
    }

}

essa é a menssagem no console

2024-06-25T20:31:00.463-03:00  INFO 17152 --- [nio-8080-exec-3] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-06-25T20:31:00.463-03:00  INFO 17152 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2024-06-25T20:31:00.465-03:00  INFO 17152 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms

Na classe SecurityFilter:

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

Faltou o espaço em branco após a palavra Bearer. Código correto:

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

E na classe SecurityConfigurations faltou adicionar o SecurityFilter nas configurações:

@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();
}

Precisa injetar o securityFilter como um atributo:

@Autowired
private SecurityFilter securityFilter;

Fiz as alteracoes mas recebi um NullPointerException java.lang.NullPointerException: Cannot invoke "org.springframework.security.core.userdetails.UserDetails.getAuthorities()" because "usuario" is null a mensagem fala que o erro esta aqui porem eu nao sei oque colocar no lugar do null mesmo sabendo que usar o null não é uma boa pratica var authentication = new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities());

solução!

Ah tem um erro no seu método geraToken da classe TokenService:

.withSubject(usuario.getSenha())

Está setando a senha no Subject, ao invés do login

Funcionou, obrigado professor