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

Authentication Manager nas versões novas

Bom dia, estou a umas 3 semanas em busca da solução de como fazer o Security Configuration rodar, estou utilizando um FilterChain mas toda hora que resolvo um erro me vem outros 10 diferentes, alguém poderia me ajudar por favor, recorri a varias paginas e ate as IA'S O erro é basicamente a Instancia do AuthenticationManager se eu configuro ele ou crio um Bean ele da erro quando passado para o filtro personalizado que roda antes do UsernamePasswordAuthenticationFilter Description:

Parameter 1 of method filterChain in br.com.claudiano.forum.config.SecurityConfiguration required a bean of type 'org.springframework.security.authentication.AuthenticationManager' that could not be found.

Action: Consider defining a bean of type 'org.springframework.security.authentication.AuthenticationManager' in your configuration.

Process finished with exit code 0 se eu inicio ele no construtor da class SecurityConfiguration ele da erro, poderiam me ajudar por favor package br.com.claudiano.forum.config

import br.com.claudiano.forum.security.JWTAuthenticationFilter import br.com.claudiano.forum.security.JWTLoginFilter import br.com.claudiano.forum.service.UsuarioService import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.HttpMethod import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter import org.springframework.web.filter.OncePerRequestFilter

@Configuration @EnableWebSecurity class SecurityConfiguration( private val usuarioService: UsuarioService, private val jwtUtil: JWTUtil, private val authManager: AuthenticationManager ) {

@Bean
fun filterChain(http: HttpSecurity, authManager: AuthenticationManager): SecurityFilterChain {

     http.authorizeHttpRequests {it
        .requestMatchers(HttpMethod.POST,"/topicos").permitAll()
        ?.anyRequest()
        ?.authenticated()
    }
         .addFilterBefore(JWTLoginFilter(authManager = authManager, jwtUtil = jwtUtil), UsernamePasswordAuthenticationFilter().javaClass)
         .addFilterBefore(JWTAuthenticationFilter(jwtUtil = jwtUtil), OncePerRequestFilter::class.java)
    return http.build()
}

// @Bean // fun authManager(http: HttpSecurity): AuthenticationManager { // val authBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java) // authBuilder.userDetailsService(usuarioService).passwordEncoder(bCryptPasswordEncoder()) // return authBuilder.build() // }

fun configure(http: HttpSecurity): AuthenticationManager {
    val authBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java)
    authBuilder.userDetailsService(usuarioService).passwordEncoder(bCryptPasswordEncoder())
    return authBuilder.build()
}

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

}

4 respostas
solução!

Olá Claudiano, tudo joia?

Vamos tentar resolver isso juntos. Pelo que você descreveu, parece que o problema está na configuração do AuthenticationManager e na forma como ele está sendo injetado.

Vou sugerir uma abordagem que pode ajudar a resolver esse problema. Vamos criar um Bean para o AuthenticationManager e ajustá-lo na configuração de segurança. Vou fornecer um exemplo prático para isso:

  1. Definindo o AuthenticationManager como um Bean:

    @Bean
    fun authenticationManager(http: HttpSecurity): AuthenticationManager {
        val authBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java)
        authBuilder.userDetailsService(usuarioService).passwordEncoder(bCryptPasswordEncoder())
        return authBuilder.build()
    }
    
  2. Ajustando a SecurityConfiguration para usar o AuthenticationManager definido:

    @Configuration
    @EnableWebSecurity
    class SecurityConfiguration(
        private val usuarioService: UsuarioService,
        private val jwtUtil: JWTUtil
    ) {
    
        @Bean
        fun filterChain(http: HttpSecurity, authManager: AuthenticationManager): SecurityFilterChain {
            http.authorizeHttpRequests { it
                .requestMatchers(HttpMethod.POST, "/topicos").permitAll()
                .anyRequest().authenticated()
            }
            .csrf().disable()
            .addFilterBefore(JWTLoginFilter(authManager = authManager, jwtUtil = jwtUtil), UsernamePasswordAuthenticationFilter::class.java)
            .addFilterBefore(JWTAuthenticationFilter(jwtUtil = jwtUtil), UsernamePasswordAuthenticationFilter::class.java)
            return http.build()
        }
    
        @Bean
        fun authenticationManager(http: HttpSecurity): AuthenticationManager {
            val authBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java)
            authBuilder.userDetailsService(usuarioService).passwordEncoder(bCryptPasswordEncoder())
            return authBuilder.build()
        }
    
        @Bean
        fun bCryptPasswordEncoder(): BCryptPasswordEncoder {
            return BCryptPasswordEncoder()
        }
    }
    

Aqui estão as mudanças importantes:

  • Criei um Bean para o AuthenticationManager chamado authenticationManager.
  • Removi o AuthenticationManager do construtor da classe SecurityConfiguration.
  • Ajustei o método filterChain para receber o AuthenticationManager como parâmetro.

Essa abordagem deve ajudar a resolver o problema de injeção do AuthenticationManager. Tente aplicar essas mudanças e veja se o problema persiste, caso não solucione peço que compartilhe todo o seu projeto, usando o GitHub ou Drive do Google. Para que assim eu consiga realizar testes para identificar o problema.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Só tenho uma duvida, a linha que eu adiciono o filtro

.addFilterBefore(JWTAuthenticationFilter(jwtUtil = jwtUtil), UsernamePasswordAuthenticationFilter::class.java)

é correto isso mesmo porque na aula era adicionado a class OncePerRequestFilter

.addFilterBefore(JWTAuthenticationFilter(jwtUtil = jwtUtil), OncePerRequestFilter::class.java)

com essa alteração que você fez ele subiu a aplicação, mas tem alguma diferença ?

O professor dá uma explicada aqui: https://cursos.alura.com.br/course/kotlin-spring-seguranca-infraestrutura/task/95345 Minuto 3:19.

Colocamos o OncePerRequestFilter como o segundo argumento do addFilterBefore(). Porém, ele não vai funcionar, porque ele espera um filtro que seja uma classe. Precisamos de uma Class que estenda um filter.
O OncePerRequestFilter é uma classe abstrata, então não vai servir como segundo argumento para o addFilterBefore().
Em vez dela, vamos continuar usando o UsernamePasswordAuthenticationFilter(), como fizemos no filtro anterior.

Se você está lidando com cenários onde há chamadas assíncronas ou encaminhamento de requisições que precisam ser tratados de forma única por requisição, então o filtro OncePerRequestFilter é útil. Ele garante que seu código de filtro seja executado apenas uma vez por cada requisição HTTP, independentemente de quantas vezes a requisição seja encaminhada internamente no servidor.

Por outro lado, o UsernamePasswordAuthenticationFilter é ideal quando você precisa de um filtro especializado para lidar especificamente com a autenticação de usuários. Ele oferece métodos separados para gerenciar o processo de autenticação e para retornar um objeto que representa a autenticação do usuário . Isso permite que você se concentre na lógica de autenticação sem se preocupar com o encadeamento correto dos filtros dentro da cadeia de processamento da requisição.

Como na aula foi feito realmente isso, uma autenticação usando usuário e senha via /login do próprio SpringSecurity, o UsernamePasswordAuthenticationFilter é a melhor opção.

Muito obrigado a vocês Armano Barros Alves Junior e Matheus Magalhães por sanarem minhas duvidas, agora vou conseguir prosseguir com as aulas.