Autenticação com SpringBoot e Token JWT

Fala pessoal,
Sou novato no java, estou com um projeto a fim de praticar/treinar e ao tentar fazer um método de autenticação com SpringBoot e JWT não estou conseguindo, atualmente ele nem deixa o projeto subir, da o erro abaixo:

APPLICATION FAILED TO START
***************************

Description:

Field authenticationManager in com.luan.config.SecurityConfig required a bean of type 'org.springframework.security.authentication.AuthenticationManager' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

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

estou utilizando a versão 6.0.1 do Spring Security e a versão 0.9.1 do JWT conforme pom.xml abaixo:

	<dependency>
		<groupId>io.jsonwebtoken</groupId>
		<artifactId>jjwt</artifactId>
		<version>0.9.1</version>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	</dependency>

A classe que eu suspeito estar com erro é essa abaixo:

@EnableWebSecurity
@Configuration
public class SecurityConfig {		
	
	@Autowired
	private JWTUtil jwtUtil;
	
	@Autowired
	private AuthenticationManager authenticationManager;
	
	@Autowired
	private UserDetailsService userDetailsService;

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {		
		
		http.addFilter(new JWTAuthenticationFilter(authenticationManager, jwtUtil));
		
		
		http.httpBasic().and().authorizeHttpRequests()
		
		.requestMatchers(HttpMethod.POST, "/postsblog/**").permitAll()		
		.requestMatchers(HttpMethod.GET).permitAll()		
		.requestMatchers(HttpMethod.DELETE).hasRole("ADMIN")
		.requestMatchers(HttpMethod.PUT).permitAll()				
		.anyRequest().authenticated()
		.and().csrf().disable()
		.cors().disable();
		return http.build();
	}	

	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*").allowedMethods("*").exposedHeaders("*");
	}	

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
		}
	
	@Bean(name = "authenticationManager")
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}
		
}

Mais especificamente, acredito que seja algum problema no ultimo método, o AuthenticationManagerBuilder, já tentei resolver de algumas formas e não consegui, pesquisando na internet só encontrei conteudo com Spring Security antigo extendendo o WebSecurityConfigAdapter.

Se alguém puder ajudar, agradeço desde já.

Provavelmente isso acontece porquê este método não fornece um bean válido, pois o retorno dele é void, normalmente ele deveria retornar uma instância de um objeto do tipo AuthenticationManager.

Nas versões mais recentes do Spring como a 3 por exemplo, é algo semelhante a isso que é implementado para fornecer um bean válido:

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
    return config.getAuthenticationManager();
}

Como você está estudando e aprendendo sobre, no github você consegue encontrar diversos projetos de exemplo que podem te orientar em alguns caminhos.

1 curtida

Primeiramnete obrigado pela ajuda, tentei fazer a alteração conforme sugeriu, mas segue dando erro, mudou o erro.
Já tentei encontrar soluções no Git Hub, em outros foruns mas nao consegui, estou travado aqui a um bom tempo. agora está com o erro abaixo, saberia me dizer onde está o problema no meu codigo?

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌──->──┐
|  securityConfig (field private org.springframework.security.authentication.AuthenticationManager com.luan.config.SecurityConfig.authenticationManager)
└──<-──┘


Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

Minha classe SecurityConfi está assim:

@EnableWebSecurity
@Configuration
public class SecurityConfig {

	@Autowired
	private JWTUtil jwtUtil;

	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired
	private UserDetailsService userDetailsService;

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

		http.addFilter(new JWTAuthenticationFilter(authenticationManager, jwtUtil));
			

		http.httpBasic().and().authorizeHttpRequests().requestMatchers(HttpMethod.POST, "/postsblog/**").permitAll()
				.requestMatchers(HttpMethod.GET).permitAll().requestMatchers(HttpMethod.DELETE).hasRole("ADMIN")
				.requestMatchers(HttpMethod.PUT).permitAll().anyRequest().authenticated().and().csrf().disable().cors()
				.disable();

		return http.build();
	}

	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*").allowedMethods("*").exposedHeaders("*");
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
			throws Exception {
		return authenticationConfiguration.getAuthenticationManager();
	}
}

Se você observar e ler o erro ele diz claramente que você tem uma referência cíclica!

Você não pode solicitar uma instancia do AuthenticationManager na mesma classe em que você habilita a construção do Bean.

Estava bem na minha cara o motivo, kkkkkkk
@Jonathan_Medeiros Obrigado!

Não sei se meu código ficou 100% certo, mas está funcional, vou deixar abaixo como ficou quem sabe pode ser útil para alguem no futuro.

´´´
@EnableWebSecurity
@Configuration
public class SecurityConfig {

@Autowired
private JWTUtil jwtUtil;

@Autowired
private UserDetailsService userDetailsService;	

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	
	http.headers().frameOptions().disable();		
	
	http.addFilter(new JWTAuthenticationFilter(authenticationManager(http.getSharedObject(AuthenticationConfiguration.class)), jwtUtil));	
	http.addFilter(new JWTAuthorizationFilter(authenticationManager(http.getSharedObject(AuthenticationConfiguration.class)), jwtUtil, userDetailsService));
	
	http.httpBasic().and().authorizeHttpRequests()
	.requestMatchers(HttpMethod.POST, "/login").permitAll()
	.requestMatchers(HttpMethod.GET).permitAll()		
	.requestMatchers(HttpMethod.GET, "/h2-console/**").permitAll()
	.anyRequest().authenticated().and().csrf().disable().cors().disable();
	
	http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
	
	return http.build();	
}

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}

public void addCorsMappings(CorsRegistry registry) {
	registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*").allowedMethods("*").exposedHeaders("*");
}

@Bean
public PasswordEncoder passwordEncoder() {
	return new BCryptPasswordEncoder();
}

}
´´´