Today, when implementing Spring Security to integrate multiple authentication methods: password mode + verification code mode, the password mode returns to execution normally and returns Token, verification code mode: always prompts the above error message: ProviderNotFoundException: No AuthenticationProvider found for ****
problem solved:
The error code occurs at line 235 of the ProviderManager.authenticate() method, and the error source code output is as follows:
The source code has identified the cause of the error: provider.authenticate(authentication) code in provider is null or parent.authenticate(authentication) code in parent is null to trigger an error message.
Detailed analysis of instantiation of ProviderManager.java class:
The first step: There is a config method in the WebSecurityConfigurerAdapter adapter class
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 加入自定义的安全认证
auth.userDetailsService(this.authUserDetailsService)
.passwordEncoder(this.passwordEncoder())
.and()
.authenticationProvider(smsAuthenticationProvider())
.authenticationProvider(authenticationProvider());
}
Step 2: You can add the AuthenticationProvider authentication object through the authenticationProvider method of the AuthenticationManagerBuilder object, look at the authenticationProvider method:
private List<AuthenticationProvider> authenticationProviders = new ArrayList<>();
public AuthenticationManagerBuilder authenticationProvider(
AuthenticationProvider authenticationProvider) {
this.authenticationProviders.add(authenticationProvider);
return this;
}
Step 3: The above is to add the AuthenticationProvider object to the authentication chain, the following code is to create the ProviderManager object and initialize the authentication connection:
@Override
protected ProviderManager performBuild() throws Exception {
if (!isConfigured()) {
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(authenticationProviders,
parentAuthenticationManager);
if (eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
}
if (eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(eventPublisher);
}
providerManager = postProcess(providerManager);
return providerManager;
}
Through the above three steps, complete the ProviderManager instantiation process.
error code:
WebSecurityConfig configuration:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailServiceImpl")
private UserDetailsService userDetailService;
/**
* 自定义Provider
*/
@Autowired
private VerificationCodeProvider verificationCodeProvider;
/**
* 认证
*
* @return
*/
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
//对默认的UserDetailsService进行覆盖
authenticationProvider.setUserDetailsService(userDetailService);
authenticationProvider.setPasswordEncoder(new PasswordEncoder() {
// 对密码未加密
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
// 判断密码是否正确, rawPassword 用户输入的密码, encodedPassword 数据库DB的密码,当 userDetailService的loadUserByUsername方法执行完后执行
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.toString().equalsIgnoreCase(encodedPassword);
}
});
return authenticationProvider;
}
}
In the above configuration file, two Providers are defined, but only the DaoAuthenticationProvider instantiation is found successfully in the code trace, and the other one fails.
Correct code:
WebSecurityConfig configuration:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailServiceImpl")
private UserDetailsService userDetailService;
/**
* 自定义Provider
*/
@Autowired
private VerificationCodeProvider verificationCodeProvider;
/**
* 认证
*
* @return
*/
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
//对默认的UserDetailsService进行覆盖
authenticationProvider.setUserDetailsService(userDetailService);
authenticationProvider.setPasswordEncoder(new PasswordEncoder() {
// 对密码未加密
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
// 判断密码是否正确, rawPassword 用户输入的密码, encodedPassword 数据库DB的密码,当 userDetailService的loadUserByUsername方法执行完后执行
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.toString().equalsIgnoreCase(encodedPassword);
}
});
return authenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
auth.authenticationProvider(authenticationProvider());
auth.authenticationProvider(verificationCodeProvider);
}
}
Problem solved