Spring Security gerenciamento de autenticação de login personalizado e lançamento de informações personalizadas

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

 

Acho que você gosta

Origin blog.csdn.net/CarryBest/article/details/102929683
Recomendado
Clasificación