Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Tomando '403 Forbidden' com httpBasic authentication

Estou tomando um '403 Forbidden' na chamada com httpBasic via Insomnia e ainda não descobri o que está errado; mesmo utilizando a mesma configuração da aula ainda assim recebo o formulário de login se fizer um GET via browser para as URIs /topicos e/ou /topicos/{id}. Obs: se no formulário de login via browser eu utilizar o email e senha cadastrado no banco consigo autenticar e receber um body vazio ou um 404 se passar um id qualquer.

ALTER TABLE usuario ADD COLUMN password text;
UPDATE usuario SET password = '$2a$12$3ilD9q6f6DqNeUMM55cffuhmHJ0dqN1rKTSwxNKPvc77iUMI.2sY.' WHERE id = 1;
@Entity
data class Usuario(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null,
    val nome: String,
    val email: String,
    val password: String
)
@Configuration
@EnableWebSecurity
class SecurityConfiguration(
    private val userDetailsService: UserDetailsService
) : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity?) {
        http?.
        authorizeRequests()?.
        antMatchers("/topicos")?.hasAuthority("LEITURA_ESCRITA")?.
        anyRequest()?.
        authenticated()?.
        and()?.
        sessionManagement()?.sessionCreationPolicy(SessionCreationPolicy.STATELESS)?.
        and()?.
        formLogin()?.disable()?.
        httpBasic()
    }

    override fun configure(auth: AuthenticationManagerBuilder?) {
        auth?.userDetailsService(userDetailsService)?.passwordEncoder(bCryptPasswordEncoder())
    }

@Bean
    fun bCryptPasswordEncoder(): BCryptPasswordEncoder {
        return BCryptPasswordEncoder()
    }

}
interface UsuarioRepository : JpaRepository<Usuario, Long> {
fun findByEmail(username: String?): Usuario?
}
@Service
class UsuarioService(
    private val repository: UsuarioRepository
): UserDetailsService {

    fun buscarPorId(id: Long): Usuario {
        return repository.getReferenceById(id)
    }

    override fun loadUserByUsername(username: String?): UserDetails {
        val usuario = repository.findByEmail(username) ?: throw RuntimeException()
        return UserDetail(usuario)
    }
}
class UserDetail(
    private val usuario: Usuario
): UserDetails {

    override fun getAuthorities(): MutableCollection<out GrantedAuthority>? = null

    override fun getPassword(): String = usuario.password

    override fun getUsername(): String = usuario.email

    override fun isAccountNonExpired(): Boolean = true

    override fun isAccountNonLocked(): Boolean = true

    override fun isCredentialsNonExpired(): Boolean = true

    override fun isEnabled(): Boolean = true
}

Não sei se passei batido em algum detalhe besta, mas a questão é que não está funcionando como deveria ... Se alguém puder passar uma dica eu agradeço ... Vlw!

1 resposta
solução!

Salve, pessoal!

Aparentemente consegui resolver o problema do 403 Forbidden aqui com uma dica do Leonardo José da Cunha Peixoto compartilhada aqui no fórum do curso através do artigo WebSecurityConfigurerAdapter deprecated - nova implementação. Além de deixar a nova implementação com o método filterChain(), ele ainda compartilhou o artigo Spring Security without the WebSecurityConfigurerAdapter com mais detalhes sobre essa nova abordagem.

No entanto, mesmo com essa nova configuração eu ainda recebia um 403 Forbidden quando realizava um POST ou PUT na aplicação; o que supostamente foi contornado (não sei se é a abordagem correta a ser aplicada) seguindo as dicas do post Spring Security configuration: HTTP 403 error, no Stack Overflow, que aborda um pouco sobre a desativação da verificação de CSRF, e permitiu que todos os endpoints respondessem como experado, exceto quando realizado um POST ou PUT, que ao invés do 403 Forbidden, a aplicação passou a retornar um 401 Unauthorized: o mesmo comportamento que obtive executando o projeto disponibilizado com o código da aula 2.

Para mais informações sobre CSRF, sugiro o artigo Cross-Site Request Forgery (CSRF) e abordagens para mitigá-lo .

Segue como ficou a classe SecurityConfiguration:

@Configuration
@EnableWebSecurity
class SecurityConfiguration {

    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http
            .csrf().disable()
            .authorizeHttpRequests()
            .antMatchers("/topicos").hasAuthority("LEITURA_ESCRITA")
            .anyRequest().authenticated()
            .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and().formLogin().disable()
            .httpBasic()
        return http.build()
    }

    @Bean
    fun encoder(): PasswordEncoder? {
        return BCryptPasswordEncoder()
    }

}

Espero que ajude mais alguém!

Obs: projeto com Spring Boot 2.7.3

Repo com o projeto: WybsonSantana/formacao-kotlin-spring-boot-alura