1. Introduction

Welcome to the Spring Security Hands-on series of articles. One of the first things we will probably deal with when integrating the Spring Security framework is customizing login registrations based on the actual needs of our project, especially Http login authentication. According to the previous article introduces, Http login authentication by filter UsernamePasswordAuthenticationFilter for processing. We have to figure out this filter before we can do some customization. Today we will briefly analyze its source code and workflow.

2. UsernamePasswordAuthenticationFilter source code analysis

UsernamePasswordAuthenticationFilter inheritance in AbstractAuthenticationProcessingFilter (article analysis). Its role is to intercept the login request and get the account and password, and then the password is encapsulated into the authentication credentials UsernamePasswordAuthenticationToken, then put the credentials to the specific configuration of the AuthenticationManager to certification. Source code analysis is as follows:

public class UsernamePasswordAuthenticationFilter extends
      AbstractAuthenticationProcessingFilter {
    // Take the key of the account name and password by default
	public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
	public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
    // This can be changed using the corresponding set method
	private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
	private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
    // Only POST requests are supported by default
	private boolean postOnly = true;
    
   // Initialize a user password authentication filter. The default login URI is /login. The request mode is POST
   public UsernamePasswordAuthenticationFilter(a) {
      super(new AntPathRequestMatcher("/login"."POST"));
   }

    / / to realize its parent class AbstractAuthenticationProcessingFilter provide hook method Use to certification
   public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
       // Check whether the request is POST
      if(postOnly && ! request.getMethod().equals("POST")) {
         throw new AuthenticationServiceException(
               "Authentication method not supported: " + request.getMethod());
      }
      
       // Get the account name and password from the HttpServletRequest object
      String username = obtainUsername(request);
      String password = obtainPassword(request);

      if (username == null) {
         username = "";
      }

      if (password == null) {
         password = "";
      }

      username = username.trim();

       // Then encapsulate the account name and password into an authentication Token object, which is a pass. However, this state is not trusted. Once authenticated, it becomes trusted
      UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
            username, password);

      Request.getremoteaddr () Request.getSession is stored in Token
      setDetails(request, authRequest);

       // The Token is then authenticated using AuthenticationManager in the parent class
      return this.getAuthenticationManager().authenticate(authRequest);
   }
   If you want to change the way you get your password, either rewrite it here, or use a custom pre-filter to make sure you get it here
   @Nullable
   protected String obtainPassword(HttpServletRequest request) {
      return request.getParameter(passwordParameter);
   }

      If you want to change the way you get your password, either rewrite it here, or use a custom pre-filter to make sure you get it here
   @Nullable
   protected String obtainUsername(HttpServletRequest request) {
      return request.getParameter(usernameParameter);
   }

   // See the corresponding instructions above to set some request details for credentials
   protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
      authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
   }

   // Set the key of the account parameter
   public void setUsernameParameter(String usernameParameter) {
      Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
      this.usernameParameter = usernameParameter;
   }

   // Set the key of the password parameter
   public void setPasswordParameter(String passwordParameter) {
      Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
      this.passwordParameter = passwordParameter;
   }

   // Only POST requests are supported
   public void setPostOnly(boolean postOnly) {
      this.postOnly = postOnly;
   }

   public final String getUsernameParameter(a) {
      return usernameParameter;
   }

   public final String getPasswordParameter(a) {
      returnpasswordParameter; }}Copy the code

In order to enhance the understanding of the process, I have drawn a picture to clearly illustrate the process:

3. What can we customize

According to the above process, we understand the UsernamePasswordAuthenticationFilter workflow can do these things:

  • Customize our login request URI and request method.

  • Format customization of login request parameters, such as submitting in JSON format or even co-existing.

  • How will the user name and password into the credential UsernamePasswordAuthenticationToken, custom business scenario requires special credentials.

4. What questions do we have

Where does the AuthenticationManager come from, what is it, how does it authenticate credentials, what are the subsequent details of authentication success, and what are the subsequent details of authentication failure? Don’t go away, but stay tuned: Here’s the answer.

Follow our public id: Felordcn for more information

Personal blog: https://felord.cn