SpringSecurity authentication process

Preface

After understanding the core components of SpringSecurity through the above , you can further understand its authentication implementation process.

Authentication entry (filter)

The authentication logic handled in SpringSecurity is UsernamePasswordAuthenticationFilterimplemented in this filter. UsernamePasswordAuthenticationFilterInherited from AbstractAuthenticationProcessingFilterthis parent class.

image.png

There is UsernamePasswordAuthenticationFilterno doFilter method implemented, so the authentication logic needs to look AbstractAuthenticationProcessingFilterat the doFilter method first.

image.png

The core code above is

Authentication authenticationResult = attemptAuthentication(request, response);

attemptAuthenticationThe function of the method is to obtain Authenticationthe object corresponding to the authentication process. Enter it UsernamePasswordAuthenticationFilterto view the specific implementation.

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
    
    
		if (this.postOnly && !request.getMethod().equals("POST")) {
    
    
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}
		String username = obtainUsername(request);
		username = (username != null) ? username : "";
		username = username.trim();
		String password = obtainPassword(request);
		password = (password != null) ? password : "";
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}

The meaning of the above code is very clear

  1. This method only supports requests submitted through POST.
  2. Get account and password
  3. Obtained UsernamePasswordAuthenticationTokenthe object through account password
  4. Set request details
  5. AuthenticationManagerComplete the authentication operation by

An object appears in the above logicAuthenticationManager

Authentication Manager

AuthenticationManagerThe interface defines a method authenticateto handle authentication requests.

public interface AuthenticationManager {
    
    

	Authentication authenticate(Authentication authentication) throws AuthenticationException;

}

Authenticator description

AuthenticationManagerThe default implementation of is ProviderManager, and the operation implemented in the method is to loop through the member ProviderManagervariables . If one of the functions returns true, the function authentication will be called . If the authentication is successful, the entire authentication process will end. If it is unsuccessful, continue to use the next suitable one for authentication. As long as one authentication is successful, the authentication is successful.authenticateList<AuthenticationProvider> providersprovidersAuthenticationProvidersupportsAuthenticationProviderauthenticateAuthenticationProvider

image.png

The default implementation provided in the current environment is

image.png

Implementation of the default authenticator

AbstractUserDetailsAuthenticationProviderAuthentication method to enter

image.png

Then enter retrieveUserthe method. The specific implementation is that DaoAuthenticationProviderour getUserDetailsServicecustomized UserServiceImplobject will be obtained, that is, our customized authentication method will be used.

	@Override
	protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
    
    
		prepareTimingAttackProtection();
		try {
    
    
     
			UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
			if (loadedUser == null) {
    
    
				throw new InternalAuthenticationServiceException(
						"UserDetailsService returned null, which is an interface contract violation");
			}
			return loadedUser;
		}
		catch (UsernameNotFoundException ex) {
    
    
			mitigateAgainstTimingAttack(authentication);
			throw ex;
		}
		catch (InternalAuthenticationServiceException ex) {
    
    
			throw ex;
		}
		catch (Exception ex) {
    
    
			throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
		}
	}

If the account exists, password verification will start, but a check will still be completed before password verification.

image.png

image.png

Then there is the specific password verification

additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);

Specific verification logic

	protected void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
    
    
        // 密码为空
		if (authentication.getCredentials() == null) {
    
    
			this.logger.debug("Failed to authenticate since no credentials provided");
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
        // 获取表单提交的密码
		String presentedPassword = authentication.getCredentials().toString();
		// 表单提交的密码和数据库查询的密码 比较是否相对
		if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
    
    
			this.logger.debug("Failed to authenticate since password does not match stored value");
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
	}

The above logic will be processed through the corresponding password encoder. If it is non-encrypted, it will be processed through NoOpPasswordEncoder.

    public boolean matches(CharSequence rawPassword, String encodedPassword) {
    
    
        return rawPassword.toString().equals(encodedPassword);
    }

image.png

If there is encryption processing, select the corresponding encryption object to process, such as the BCryptPasswordEncoder used to get started with SpringSecurity.

image.png

Summarize

Spring Security certification process:

  1. The request first goes to the filter, which is used to verify that the system sets filters for restricted resources.
  2. After the request is received by the filter, it is passed to the AuthenticationProvider. AuthenticationProvider requires user information and the authentication implementation of UserDetailsService.
  3. UserDetailsService is inherited by UserDetail, which encapsulates User user information. At this stage, user information is encapsulated into AuthenticationProvider.
  4. Next, the AuthenticationProvider that encapsulates the user information will be passed to the ProviderManager in the AuthenticationManager.
    ProviderManager will review the AuthenticationProvider again and finally return the filter.

Through Spring Security's authentication implementation, you can see that although the code is concise and clear, it is extremely scalable. Spring Security supports multiple authentication and authorization mechanisms, including username and password authentication, JWT token authentication, OAuth2 authentication, etc. At the same time, Spring Security also provides a variety of default configurations that can be adjusted and expanded as needed.

Guess you like

Origin blog.csdn.net/qq_28314431/article/details/132979838