Gestión de autenticación de inicio de sesión personalizada de Spring Security y arrojar información personalizada

El filtro predeterminado para el procesamiento de autenticación por seguridad es UsernamePasswordAuthenticationFilter . Al mirar el código fuente, puede ver que el método para el procesamiento de autenticación es intentoAuthentication . La función principal de este método es encapsular la cuenta y la contraseña ingresadas por el usuario en un UsernamePasswordAuthenticationToken y luego use el método setDetails para Este objeto está almacenado, y luego llame al método this.getAuthenticationManager (). authenticate (authRequest) para devolver un objeto Authentication . Muchas otras clases llamadas por este proceso this.getAuthenticationManager (). Authenticate (authRequest) son las siguientes:

UsernamePasswordAuthenticationFilter -> ProviderManager -> AbstractUserDetailsAuthenticationProvider -> DaoAuthenticationProvider -> JdbcDaoImpl

Encontré una imagen de Internet y la publiqué:

 

1: Después de ingresar el nombre de usuario y la contraseña, haga clic en iniciar sesión para acceder al método de intento de autenticación de UsernamePasswordAuthenticationFilter , que es la entrada para iniciar sesión

2: Llamada ProviderManager El autenticar método y ProviderManager confiados a AbstractUserDetailsAuthenticationProvider de autenticar a hacer, entonces AbstractUserDetailsAuthenticationProvider su vez llama DaoAuthenticationProvider en retrieveUser , en DaoAuthenticationProvider clase retrieveUser enfoque, ya que para llegar introducido un nombre de usuario DetallesUsuario , por lo que la llamada La loadUserByUsername método en el JdbcDaoImpl , este método devuelve un usuario consultado ( UserDetails ) a su llamador , y finalmente se obtendrá un UserDetails en el método de autenticación de AbstractUserDetailsAuthenticationProviderUsuario de objeto ,

3: Luego ejecute preAuthenticationChecks.check (usuario) y additionalAuthenticationChecks (usuario, (UsernamePasswordAuthenticationToken) autenticación) en DaoAuthenticationProvider ; el primer método es juzgar si el usuario consultado está disponible o bloqueado, etc., y el segundo es juzgar al usuario consultado Si la contraseña del objeto es la misma que la contraseña de autenticación (este objeto es en realidad para almacenar el nombre de usuario y la contraseña ingresados ​​por el usuario), si es la misma, significa que el inicio de sesión es exitoso, si es incorrecto, entonces lanzar nueva BadCredentialsException (messages.getMessage ("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails); El mensaje Bad credentials es la información después de que el inicio de sesión falló

Creo que la imagen de arriba es un poco incorrecta. Puedo ver en el depurador que el método additionalAuthenticationChecks debe estar en el llamado DaoAuthenticationProvider en lugar de AbstractUserDetailsAuthenticationProvider .

===================== Línea divisoria ========================== = ==============================

De lo anterior, podemos ver que si necesitamos modificar las reglas de autenticación o personalizar la excepción de falla de autenticación de contraseña, podemos anular el método adicionalAuthenticationChecks heredando DaoAuthenticationProvider y luego inyectar nuestra propia clase AuthenticationProvider .

El primer paso: heredar DaoAuthenticationProvider y anular el método additionalAuthenticationChecks

Moví el método de DaoAuthenticationProvide y lo cambié según mis propias necesidades. En la actualidad, se agrega una excepción de error de contraseña. Puede verificar la contraseña de acuerdo con sus necesidades. Cabe señalar que no mueva la siguiente línea de código,

public DaoAuthenticationProvider () {

   setPasswordEncoder (PasswordEncoderFactories.createDelegatingPasswordEncoder ());

}

Debido a que PasswordEncoderFactories.createDelegatingPasswordEncoder () en DaoAuthenticationProvide llama a BCryptPasswordEncoder, pero en mi propio código, llama a DelegatingPasswordEncoder.
Aún no se conoce el motivo específico. Esto provocará que la verificación de la contraseña falle, así que creé un nuevo BCryptPasswordEncoder para la calibración.

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",
                    "密码错误!"));
        }

    }


}

Dos: inyecte su propia AuthenticationProvide

Hay dos formas, la primera es inyectar
@Override de la misma forma que el userDetailsService personalizado

La configuración vacía protegida (autenticación AuthenticationManagerBuilder) arroja una excepción {

    // auth.authenticationProvider (nuevo SelfLoginAuthenticationProvider (userDetailsService));

    auth.userDetailsService (userDetailsService) .passwordEncoder (nuevo BCryptPasswordEncoder ());
}

Pero este tipo de problema es que habrá múltiples AuthenticationProvide, y usted siempre será el primero en llamar al suyo, y finalmente llamar al suyo, por lo que sobrescribirá el suyo.

El segundo reescribe el administrador de autenticación AuthenticationManager en WebSecurityConfigurerAdapter

 @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        ProviderManager authenticationManager = new ProviderManager(Arrays.asList(selfLoginAuthenticationProvider));
        authenticationManager.setEraseCredentialsAfterAuthentication(false);
        return authenticationManager;
    }
通过源码看出里面有2个方法,需要用第一个方法而不要用第二个,这样就会使用自己自定义的SelfLoginAuthenticationProvider

De esta manera, puede personalizar el procesamiento de la solicitud de inicio de sesión.
Se requieren las tres áreas y pasos principales.
1: Heredar DaoAuthenticationProvide y reescribir additionalAuthenticationChecks
2: Vuelva a escribir el administrador de autenticación AuthenticationManager en WebSecurityConfigurerAdapter para asegurarse de que solo se use su propio AuthenticationProvide
3: Cree un BCryptPasswordEncoder usted mismo para la verificación de contraseña. No use proxy DelegatingPasswordEncoder

 

Supongo que te gusta

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