Solucionado (ver solução)
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