SpringSecurity 密码验证流程

简介: 一、通过debug源码,解析,更加清楚的了解核心的原理,出现问题可以更好的解决 二、密码验证流程 1 默认使用 UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter 执行方法: pu.

一、通过debug源码,解析,更加清楚的了解核心的原理,出现问题可以更好的解决

二、密码验证流程

1 默认使用 UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter

  • 执行方法:

    public Authentication attemptAuthentication(HttpServletRequest request,
       HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
       throw new AuthenticationServiceException(
               "Authentication method not supported: " + request.getMethod());
        }
        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); (这里最终是AbstractAuthenticationToken)
        return this.getAuthenticationManager().authenticate(authRequest);
    } 

2 return this.getAuthenticationManager().authenticate(authRequest); 执行这个方法后,跳入到 AuthenticationManager 这个接口,以其一个实现类来实现这个方法。

   Authentication authenticate(Authentication authentication) throws AuthenticationException;

3 ProviderManager implements AuthenticationManager, MessageSourceAware,InitializingBean

    public Authentication authenticate(Authentication authentication)
               throws AuthenticationException {
           Class<? extends Authentication> toTest = authentication.getClass();
           AuthenticationException lastException = null;
           Authentication result = null;
           boolean debug = logger.isDebugEnabled(); 
           --AuthenticationProvider 校验的是这个对象
           for (AuthenticationProvider provider : getProviders()) {
               if (!provider.supports(toTest)) {
                   continue;
               }
               if (debug) {
                   logger.debug("Authentication attempt using "
                           + provider.getClass().getName());
               }
               try {
                    -- 重点,这里调用了验证方法 ----  
                   result = provider.authenticate(authentication);         
                   if (result != null) {
                       copyDetails(authentication, result);
                       break;
                   }
               }
               catch (AccountStatusException e) {
                   prepareException(e, authentication);
                   // SEC-546: Avoid polling additional providers if auth failure is due to
                   // invalid account status
                   throw e;
               }
               catch (InternalAuthenticationServiceException e) {
                   prepareException(e, authentication);
                   throw e;
               }
               catch (AuthenticationException e) {
                   lastException = e;
               }
           }
           if (result == null && parent != null) {
               // Allow the parent to try.
               try {
                   result = 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 = e;
               }
           }
           if (result != null) {
               if (eraseCredentialsAfterAuthentication
                       && (result instanceof CredentialsContainer)) {
                   // Authentication is complete. Remove credentials and other secret data
                   // from authentication
                   ((CredentialsContainer) result).eraseCredentials();
               }
               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}"));
           }
           prepareException(lastException, authentication);
           throw lastException;
    }

4 进入 public interface AuthenticationProvider

    Authentication authenticate(Authentication authentication) throws AuthenticationException;

5 进入 abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware,实现了AuthenticationProvider 接口的authenticate(authentication)方法

public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
                messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.onlySupports",
                        "Only UsernamePasswordAuthenticationToken is supported"));
        // Determine username
        String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED": authentication.getName();
        boolean cacheWasUsed = true;
        UserDetails user = this.userCache.getUserFromCache(username);
        if (user == null) {
            cacheWasUsed = false;
            try {
                user = retrieveUser(username,
                        (UsernamePasswordAuthenticationToken) authentication);
            }
            catch (UsernameNotFoundException notFound) {
                logger.debug("User '" + username + "' not found");
                if (hideUserNotFoundExceptions) {
                    throw new BadCredentialsException(messages.getMessage(
                            "AbstractUserDetailsAuthenticationProvider.badCredentials",
                            "Bad credentials"));
                }
                else {
                    throw notFound;
                }
            }
            Assert.notNull(user,
                    "retrieveUser returned null - a violation of the interface contract");
        }
        try {
            preAuthenticationChecks.check(user);
            additionalAuthenticationChecks(user,
                    (UsernamePasswordAuthenticationToken) authentication);
        }
        catch (AuthenticationException exception) {
            if (cacheWasUsed) {
                // There was a problem, so try again after checking
                // we're using latest data (i.e. not from the cache)
                cacheWasUsed = false;
                user = retrieveUser(username,
                        (UsernamePasswordAuthenticationToken) authentication);
                preAuthenticationChecks.check(user);
                additionalAuthenticationChecks(user,
                        (UsernamePasswordAuthenticationToken) authentication);
            }
            else {
                throw exception;
            }
        }
        postAuthenticationChecks.check(user);
        if (!cacheWasUsed) {
            this.userCache.putUserInCache(user);
        }
        Object principalToReturn = user;
        if (forcePrincipalAsString) {
            principalToReturn = user.getUsername();
        }
        return createSuccessAuthentication(principalToReturn, authentication, user);
    }
  • 在方法中调用自身的一个抽象方法;

    protected abstract void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication)
         throws AuthenticationException;

6 通过实现该抽象类的子类 class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider,重写 additionalAuthenticationChecks方法

protected void additionalAuthenticationChecks(UserDetails userDetails,
            UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        Object salt = null;
        if (this.saltSource != null) {
            salt = this.saltSource.getSalt(userDetails);
        }
        if (authentication.getCredentials() == null) {
            logger.debug("Authentication failed: no credentials provided");
            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }
        String presentedPassword = authentication.getCredentials().toString();
        //验证密码, passwordEncoder 是客户端穿回来的密码,userDetails.getPassword()是数据库中的密码
        if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),presentedPassword, salt)) {
            logger.debug("Authentication failed: password does not match stored value");
            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }
    }

三、其他有关SpringSecurity的笔记,包括核心认识,demo地址

SpringSecurity初步学习

相关文章
|
开发框架 JavaScript 前端开发
UniApp Button讲解
UniApp Button讲解
384 1
|
负载均衡 安全 中间件
Express——结合multer上传图片、EJS
Express——结合multer上传图片、EJS
269 0
|
8月前
|
机器学习/深度学习 资源调度 计算机视觉
RT-DETR改进策略【Conv和Transformer】| CVPR-2022 Deformable Attention Transformer 可变形注意力 动态关注目标区域
RT-DETR改进策略【Conv和Transformer】| CVPR-2022 Deformable Attention Transformer 可变形注意力 动态关注目标区域
357 15
RT-DETR改进策略【Conv和Transformer】| CVPR-2022 Deformable Attention Transformer 可变形注意力 动态关注目标区域
|
存储 数据可视化 前端开发
基于python的当当二手书数据分析与可视化系统设计与实现
本文设计并实现了一个基于Python的当当二手书数据分析与可视化系统,通过数据收集、清洗、聚类分析和可视化展示,为二手书市场提供全面的数据分析和决策支持,以促进资源循环利用和市场效率优化。
389 0
基于python的当当二手书数据分析与可视化系统设计与实现
静态资源路径访问不到的问题,Whitelabel Error Page,There was an unexpected error,解决bug的好方法,大量翻看别人的文章,终究是粗心惹的祸
静态资源路径访问不到的问题,Whitelabel Error Page,There was an unexpected error,解决bug的好方法,大量翻看别人的文章,终究是粗心惹的祸
|
SQL 缓存 JavaScript
PageHelper 使用中的一些坑
PageHelper 使用中的一些坑
PageHelper 使用中的一些坑
|
Java 微服务
Java错误:微服务报错Cannot execute request on any known serve
Java错误:微服务报错Cannot execute request on any known serve
|
Java
SpringBoot整合sharding-jdbc实现分库分表
SpringBoot整合sharding-jdbc实现分库分表
552 1
|
安全 数据库 网络虚拟化
计算机网络:思科实验【4-生成树协议STP及虚拟局域网VLAN】
计算机网络:思科实验【4-生成树协议STP及虚拟局域网VLAN】