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

[Dúvida] Restrição para acessar o crud

Como faço para restringir acessos após efetuar o Login? Tentei configurar o ROLE_ADMIN e utilizar a anotação @PreAuthorize no CRUD, mas não obtive sucesso.

Meu código:

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<GrantedAuthority> authorities = new ArrayList<>();
    authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
    if (this.nivel_acesso.equals(NivelAcesso.ADMINISTRADOR)) {
        authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
    }
    return authorities;
}
    @DeleteMapping("/{id}")
    @Transactional
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity excluir(@PathVariable Long id) {
        var produto = repository.getReferenceById(id);
        produto.excluir();

        return ResponseEntity.noContent().build();
    }
@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeHttpRequests()
                .requestMatchers(HttpMethod.POST, "/login").permitAll()
                .requestMatchers(HttpMethod.DELETE, "/produtos/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and().addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

Detalhe: ele puxa do Enum o parâmetro: administrador.

9 respostas

Olá Giovanni,

Pelo que pude analisar em seu código, a configuração do ROLE_ADMIN parece estar correta. No entanto, notei que você está utilizando a expressão "ADMIN" na anotação @PreAuthorize, enquanto no método getAuthorities você definiu como "ROLE_ADMIN". Tente alterar a expressão para "hasRole('ROLE_ADMIN')" na anotação @PreAuthorize.

Além disso, verifique se o usuário que está tentando acessar o CRUD tem a permissão correta. Caso contrário, ele não conseguirá acessar mesmo com as configurações corretas.

Espero ter ajudado e bons estudos!

Olá Otávio,

Realizei as devidas alterações, mas agora está dando "403 Forbidden" quando eu tento deletar algo do CRUD como administrador. já quando eu logo com outro parâmetro do ENUM como por exemplo "cliente" ele bloqueia, então está certo, o único problema é no administrador agora.

Olá Giovanni,

O erro 403 Forbidden geralmente indica que o usuário autenticado não tem permissão para acessar o recurso solicitado. Nesse caso, pode ser que a configuração de segurança não esteja permitindo o acesso ao recurso para o ROLE_ADMIN.

Uma forma de verificar isso é debugar a configuração de segurança e verificar se a permissão ROLE_ADMIN está sendo atribuída ao usuário corretamente.

Outra coisa que pode estar causando esse erro é a ordem das configurações no método securityFilterChain. Verifique se a configuração para o DELETE está antes da configuração para o acesso autenticado.

assim está a configuração do meu securityFilterChain e filterInternal:

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeHttpRequests()
                .requestMatchers(HttpMethod.POST, "/login").permitAll()
                .requestMatchers(HttpMethod.DELETE, "/produtos/**").hasRole("ROLE_ADMIN")
                .anyRequest().authenticated()
                .and().addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }
    @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.findByEmail(subject);
            var authentication = new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        filterChain.doFilter(request, response);
    }

Olá Giovanni,

Pela sua configuração, parece que tudo está correto. O problema pode estar no usuário que você está autenticando. Verifique se o usuário possui a permissão "ROLE_ADMIN" no momento em que ele está tentando excluir o produto.

Além disso, certifique-se de que a solicitação HTTP está sendo feita com o token de autenticação correto. Você pode usar ferramentas como o Postman ou o cURL para verificar se a solicitação está sendo feita corretamente.

Espero ter ajudado!

estou passando dessa forma no postman:

{
    "email":"giovanni.rosa@trevo.com.br",
    "senha":"123456",
    "nivel_acesso":"ADMINISTRADOR"
}

ele retorna um Token e eu coloco no "Authorization Bearer Token", somente o DELETE está dando "403 Forbidden"

aqui está também minha classe completa do usuário:

package com.trevo.api.domain.usuario;

@Table(name = "usuarios")
@Entity(name = "Usuario")
@Getter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
public class Usuario implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String email;
    private String senha;
    @Enumerated(EnumType.STRING)
    private NivelAcesso nivel_acesso;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        if (this.nivel_acesso.equals(NivelAcesso.ADMINISTRADOR)) {
            authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        }
        return authorities;
    }

    @Override
    public String getPassword() {
        return senha;
    }

    @Override
    public String getUsername() {
        return email;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}
solução!

Você mencionou que está passando o nível de acesso como "ADMINISTRADOR" no corpo da requisição no Postman. Porém, o nível de acesso deve ser armazenado no banco de dados e não passado no corpo da requisição de login. A requisição de login deve conter apenas o email e a senha, enquanto o nível de acesso deve ser obtido a partir do registro do usuário no banco de dados.

Por favor, verifique se o nível de acesso "ADMINISTRADOR" está corretamente armazenado no banco de dados para o usuário "giovanni.rosa@trevo.com.br". Depois disso, tente fazer o login novamente usando apenas o email e a senha no corpo da requisição e verifique se o problema persiste.

Em qual aula você teve que implementar o código enviado? Vou dar uma olhada

Opa, estava dando uma revisada melhor e achei o problema.

O problema estava no "SecurityFilterChain", ele ficou dessa forma:

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeHttpRequests()
                .requestMatchers(HttpMethod.POST, "/login").permitAll()
                .requestMatchers(HttpMethod.DELETE, "/produtos/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and().addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

Perfeito GIovanni, obrigado por compartilhar a solução final