欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

10、spring security拦截器之UsernamePasswordAuthenticationFilter

程序员文章站 2024-03-19 15:33:04
...

UsernamePasswordAuthenticationFilter:登录验证

在SecurityConfig中对应:

http.formLogin() //表单登录
        .loginPage("/login.html") //登录页面
        .loginProcessingUrl("/login") //登录的url,默认:/login
        .usernameParameter("username") //用户名参数名称,默认:username
        .passwordParameter("password") //密码参数名称,默认:password

源码

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
      throws IOException, ServletException {

   HttpServletRequest request = (HttpServletRequest) req;
   HttpServletResponse response = (HttpServletResponse) res;
   //1、验证是否是登录url,默认值:/login
   if (!requiresAuthentication(request, response)) {
      chain.doFilter(request, response);

      return;
   }

   if (logger.isDebugEnabled()) {
      logger.debug("Request is to process authentication");
   }

   Authentication authResult;

   try {
       //2、获取认证结果Authentication
      authResult = attemptAuthentication(request, response);
      if (authResult == null) {
         // return immediately as subclass has indicated that it hasn't completed
         // authentication
         return;
      }
      //3、新的身份验证发生时的操作,可以对同时登录相同账号的用户进行限制
      sessionStrategy.onAuthentication(authResult, request, response);
   }
   catch (InternalAuthenticationServiceException failed) {
      logger.error(
            "An internal error occurred while trying to authenticate the user.",
            failed);
      unsuccessfulAuthentication(request, response, failed);

      return;
   }
   catch (AuthenticationException failed) {
      // Authentication failed
      unsuccessfulAuthentication(request, response, failed);

      return;
   }

   // Authentication success
   if (continueChainBeforeSuccessfulAuthentication) {
      chain.doFilter(request, response);
   }

   successfulAuthentication(request, response, chain, authResult);
}

attemptAuthentication():获取认证结果Authentication

public Authentication attemptAuthentication(HttpServletRequest request,
      HttpServletResponse response) throws AuthenticationException {
   if (postOnly && !request.getMethod().equals("POST")) {
      throw new AuthenticationServiceException(
            "Authentication method not supported: " + request.getMethod());
   }
  //1、获取用户名和密码
   String username = obtainUsername(request);
   String password = obtainPassword(request);

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

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

   username = username.trim();

   UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
         username, password);

   // Allow subclasses to set the "details" property
   setDetails(request, authRequest);
   //2、对请求进行验证,AuthenticationManager的实现类是ProviderManager
   return this.getAuthenticationManager().authenticate(authRequest);
}

ProviderManager.authenticate(Authentication)

public Authentication authenticate(Authentication authentication)
      throws AuthenticationException {
   Class<? extends Authentication> toTest = authentication.getClass();
   AuthenticationException lastException = null;
   AuthenticationException parentException = null;
   Authentication result = null;
   Authentication parentResult = null;
   boolean debug = logger.isDebugEnabled();
    //1、获取认证提供者AuthenticationProvider
    //这里获取的值只有AnonymousAuthenticationProvider
   for (AuthenticationProvider provider : getProviders()) {
       //2、由于AnonymousAuthenticationProvider不支持处理这个Authentication
       //继续下一个循环
      if (!provider.supports(toTest)) {
         continue;
      }

      if (debug) {
         logger.debug("Authentication attempt using "
               + provider.getClass().getName());
      }

      try {
          //2.1 如果支持,则调用认证方法
         result = provider.authenticate(authentication);

         if (result != null) {
            copyDetails(authentication, result);
            break;
         }
      }
      catch (AccountStatusException | InternalAuthenticationServiceException e) {
         prepareException(e, authentication);
         // SEC-546: Avoid polling additional providers if auth failure is due to
         // invalid account status
         throw e;
      } catch (AuthenticationException e) {
         lastException = e;
      }
   }

   //3、如果上面的认证结果为空,并且parent不为空,则调用parent.authenticate()
   if (result == null && parent != null) {
      // Allow the parent to try.
      try {
          /**
          这里和上面唯一的区别就是getProviders()获取的值不一样,
          parent里面的AuthenticationProvider实现类有DaoAuthenticationProvider,
          内部会调用UserDetailsService.loadUserByUsername()方法根据用户名加载用户,
          我们之前编写的CustomUserDetailsService类就是在这里被调用的
          */
         result = parentResult = parent.authenticate(authentication);
      }
      catch (ProviderNotFoundException e) {
         // ignore as we will throw below if no other exception occurred prior to
         // calling parent and the parent
         // may throw ProviderNotFound even though a provider in the child already
         // handled the request
      }
      catch (AuthenticationException e) {
         lastException = parentException = e;
      }
   }

   if (result != null) {
      if (eraseCredentialsAfterAuthentication
            && (result instanceof CredentialsContainer)) {
         // Authentication is complete. Remove credentials and other secret data
         // from authentication
         ((CredentialsContainer) result).eraseCredentials();
      }

      // If the parent AuthenticationManager was attempted and successful than it will publish an AuthenticationSuccessEvent
      // This check prevents a duplicate AuthenticationSuccessEvent if the parent AuthenticationManager already published it
      if (parentResult == null) {
         eventPublisher.publishAuthenticationSuccess(result);
      }
      return result;
   }

   // Parent was null, or didn't authenticate (or throw an exception).

   if (lastException == null) {
      lastException = new ProviderNotFoundException(messages.getMessage(
            "ProviderManager.providerNotFound",
            new Object[] { toTest.getName() },
            "No AuthenticationProvider found for {0}"));
   }

   // If the parent AuthenticationManager was attempted and failed than it will publish an AbstractAuthenticationFailureEvent
   // This check prevents a duplicate AbstractAuthenticationFailureEvent if the parent AuthenticationManager already published it
   if (parentException == null) {
      prepareException(lastException, authentication);
   }

   throw lastException;
}

parent.authenticate(Authentication):这里和上面唯一的区别就是getProviders()获取的值不一样,parent里面的AuthenticationProvider实现类有DaoAuthenticationProvider,内部会调用UserDetailsService.loadUserByUsername()方法根据用户名加载用户,我们之前编写的CustomUserDetailsService类就是在这里被调用的

相关标签: spring security