我正在尝试将登录和注册添加到我的 API 应用程序中。但我遇到了问题。两个bean 相互冲突。我将与这些 bean 交互的所有类都放在消息中。
2024-03-11T00:13:22.768+03:00 WARN 22820 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityController': Unsatisfied dependency expressed through method 'setAuthenticationManager' parameter 0: Error creating bean with name 'authenticationManager' defined in class path resource [com/weather/weather/config/SecurityConfigurator.class]: Failed to instantiate [org.springframework.security.authentication.AuthenticationManager]: Factory method 'authenticationManager' threw exception with message: No qualifying bean of type 'org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder' available: expected single matching bean but found 2: authenticationManagerBuilder,configureAuthenticationManagerBuilder
2024-03-11T00:13:22.769+03:00 INFO 22820 --- [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-03-11T00:13:22.771+03:00 INFO 22820 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2024-03-11T00:13:22.774+03:00 INFO 22820 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
2024-03-11T00:13:22.776+03:00 INFO 22820 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2024-03-11T00:13:22.788+03:00 INFO 22820 --- [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-03-11T00:13:22.800+03:00 ERROR 22820 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method setAuthenticationManager in com.weather.weather.controller.SecurityController required a single bean, but 2 were found:
- authenticationManagerBuilder: defined by method 'authenticationManagerBuilder' in class path resource [org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.class]
- configureAuthenticationManagerBuilder: defined by method 'configureAuthenticationManagerBuilder' in class path resource [com/weather/weather/config/SecurityConfigurator.class]
This may be due to missing parameter name information
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
Ensure that your compiler is configured to use the '-parameters' flag.
You may need to update both your build tool settings as well as your IDE.
安全配置器
@Configuration
@EnableWebSecurity
@Data
public class SecurityConfigurator {
private UserService userService;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)throws Exception{
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public AuthenticationManagerBuilder configureAuthenticationManagerBuilder(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userService).passwordEncoder(passwordEncoder());
return authenticationManagerBuilder;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(AbstractHttpConfigurer::disable)
.cors(httpSecurityCorsConfigurer ->
httpSecurityCorsConfigurer.configurationSource(request ->
new CorsConfiguration().applyPermitDefaultValues())
)
.exceptionHandling(exceptions -> exceptions.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/api/v1/weather").fullyAuthenticated()
.anyRequest().permitAll()
);
return http.build();
}
}
安全控制器
@RestController
@RequestMapping("/auth")
public class SecurityController {
private UserRepository userRepository;
private PasswordEncoder passwordEncoder;
private AuthenticationManager authenticationManager;
private JwtCore jwtCore;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Autowired
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
@Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Autowired
public void setJwtCore(JwtCore jwtCore) {
this.jwtCore = jwtCore;
}
@PostMapping("/signup")
ResponseEntity<?> signup(@RequestBody SignUpRequest signUpRequest){
if(userRepository.existsUserByUsername(signUpRequest.getUsername())){
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("This nickname already exist");
}
User user = new User();
user.setUsername(signUpRequest.getUsername());
user.setPassword(passwordEncoder.encode(signUpRequest.getPassword()));
userRepository.save(user);
return ResponseEntity.ok("Chinazes");
}
@PostMapping("/signin")
ResponseEntity<?> signin(@RequestBody SignInRequest signInRequest){
Authentication authentication = null;
try{
authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(signInRequest.getUsername(),signInRequest.getPassword()));
} catch (BadCredentialsException e){
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtCore.generateToken(authentication);
return ResponseEntity.ok(jwt);
}
}
我尝试使用
@Primary
和@Qualifier
,但它们导致了更多错误。我不明白为什么 Spring 会抱怨它,如果这些 bean 是不同的。
问题在于
@EnableWebSecurity
创建了一个 AuthenticationManagerBuilder
bean,而您也这样做了。我在本地确认,如果您用 @Primary
标记 AuthenticationManagerBuilder,错误就会消失,因为 Spring Boot 现在能够确定在您的 SecurityController
中使用哪个 bean。