O filtro padrão para processamento de autenticação por segurança é UsernamePasswordAuthenticationFilter . Observando o código-fonte, você pode ver que o método para processamento de autenticação é tryAuthentication . A principal função desse método é encapsular a conta e a senha inseridas pelo usuário em um UsernamePasswordAuthenticationT objeto e, em seguida, use o método setDetails para Este objeto é armazenado e, em seguida, chame o método this.getAuthenticationManager (). authenticate (authRequest) para retornar um objeto de autenticação . Muitas outras classes chamadas por este processo this.getAuthenticationManager (). Authenticate (authRequest) são as seguintes:
UsernamePasswordAuthenticationFilter -> ProviderManager -> AbstractUserDetailsAuthenticationProvider -> DaoAuthenticationProvider -> JdbcDaoImpl
Encontrei uma foto na Internet e postei:
1: Após inserir o nome de usuário e senha, clique em login para acessar o método tryAuthentication de UsernamePasswordAuthenticationFilter , que é a entrada para o login
2: Chamada ProviderManager O autenticar método e ProviderManager confiada a AbstractUserDetailsAuthenticationProvider de autenticar a fazer, então AbstractUserDetailsAuthenticationProvider sua vez, chama DaoAuthenticationProvider em retrieveUser , em DaoAuthenticationProvider classe retrieveUser abordagem, porque para obter um nome de usuário inserido UserDetails , para que a chamada O loadUserByUsername método em JdbcDaoImpl , este método retorna um usuário consultado ( UserDetails ) para seu chamador e, finalmente, um UserDetails será obtido no método authenticate de AbstractUserDetailsAuthenticationProviderUsuário objeto ,
3: Em seguida, execute preAuthenticationChecks.check (usuário) e additionalAuthenticationChecks (usuário, (UsernamePasswordAuthenticationToken) autenticação) em DaoAuthenticationProvider ; o primeiro método é para julgar se o usuário consultado está disponível ou bloqueado, etc., e o último é para julgar o usuário consultado Se a senha do objeto é a mesma que a senha de autenticação (este objeto é na verdade para armazenar o nome de usuário e senha digitados pelo usuário), se a mesma, significa que o login foi bem sucedido, se estiver errado, então lance new BadCredentialsException (messages.getMessage ("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails); A mensagem Bad credentials é a informação após a falha de login
Acho que a imagem acima está um pouco errada. Posso ver pelo depurador que o método additionalAuthenticationChecks deve estar no chamado DaoAuthenticationProvider em vez de AbstractUserDetailsAuthenticationProvider .
======================= Linha divisória ============================ = ================================
Do exposto, podemos ver que se precisarmos modificar as regras de autenticação ou personalizar a exceção de falha de autenticação de senha, podemos substituir o método additionalAuthenticationChecks herdando DaoAuthenticationProvider e, em seguida, injetar nossa própria classe AuthenticationProvider .
A primeira etapa: herdar DaoAuthenticationProvider e substituir o método additionalAuthenticationChecks
Mudei o método de DaoAuthenticationProvide e alterei-o para minhas próprias necessidades. No momento, uma exceção de erro de senha foi lançada. Você pode fazer a verificação de senha de acordo com suas necessidades. Deve-se observar que não mova a seguinte linha de código,
public DaoAuthenticationProvider () {
setPasswordEncoder (PasswordEncoderFactories.createDelegatingPasswordEncoder ());
}
Como PasswordEncoderFactories.createDelegatingPasswordEncoder () em DaoAuthenticationProvide chama BCryptPasswordEncoder, mas em meu próprio código, chama DelegatingPasswordEncoder. O
motivo específico ainda não é conhecido. Isso fará com que a verificação de senha falhe, então criei um novo teste BCryptPasswordEncoder para calibração.
package com.XXX.XXXX.auth.filter;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
/**
* 类描述:
*
* @author :carry
* @version: 1.0 CreatedDate in 2019年11月05日
* <p>
* 修订历史: 日期 修订者 修订描述
*/
@Component
public class SelfLoginAuthenticationProvider extends DaoAuthenticationProvider {
private static PasswordEncoder passwordEncoder;
public SelfLoginAuthenticationProvider(UserDetailsService userDetailsService) {
// 这个地方一定要对userDetailsService赋值,不然userDetailsService是null
setUserDetailsService(userDetailsService);
}
@SuppressWarnings("deprecation")
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
//使用BCryptPasswordEncoder不要使用代理DelegatingPasswordEncoder
if (null == passwordEncoder) {
passwordEncoder = new BCryptPasswordEncoder();
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"密码错误!"));
}
}
}
Dois: injete seu próprio AuthenticationProvide
Existem duas maneiras, a primeira é injetar
@Override da mesma forma que o userDetailsService personalizado
protected void configure (AuthenticationManagerBuilder auth) lança Exception {
// auth.authenticationProvider (new SelfLoginAuthenticationProvider (userDetailsService));
auth.userDetailsService (userDetailsService) .passwordEncoder (new BCryptPasswordEncoder ());
}
Mas este tipo de problema é que haverá vários AuthenticationProvide, e você sempre será o primeiro a chamar o seu e, finalmente, chamar o seu, então ele substituirá o seu
O segundo reescreve o gerenciador de autenticação AuthenticationManager em WebSecurityConfigurerAdapter
@Override
protected AuthenticationManager authenticationManager() throws Exception {
ProviderManager authenticationManager = new ProviderManager(Arrays.asList(selfLoginAuthenticationProvider));
authenticationManager.setEraseCredentialsAfterAuthentication(false);
return authenticationManager;
}
通过源码看出里面有2个方法,需要用第一个方法而不要用第二个,这样就会使用自己自定义的SelfLoginAuthenticationProvider
Desta forma, você pode personalizar o processamento da solicitação de login.As
três principais áreas e etapas são necessárias.
1: Herdar DaoAuthenticationProvide e reescrever additionalAuthenticationChecks
2: Reescrever o gerenciador de autenticação AuthenticationManager em WebSecurityConfigurerAdapter para garantir que apenas o seu próprio AuthenticationProvide seja usado
3: Crie um BCryptPasswordEncoder você mesmo para verificação de senha. Não use proxy DelegatingPasswordEncoder