返回

聊聊SpringSecurity认证流程和授权流程

发布时间:2022-09-21 22:10:59 261
# java# java# 数据库# 数据# 信息

聊聊SpringSecurity认证流程和授权流程

认证流程

我们先聊一下SpringSecurity的认证流程

首先是AbstractAuthenticationProcessingFilter的doFilter()方法

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

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    if (!requiresAuthentication(request, response)) {
      chain.doFilter(request, response);

      return;
    }


    Authentication authResult;

    try {
      authResult = attemptAuthentication(request, response);
      if (authResult == null) {
        
        return;
      }
      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()

方法中调用抽象方法attemptAuthentication()获取认证信息,实现类是UsernamePasswordAuthenticationFilter,它的attemptAuthentication()方法:

  1. 获取用户和密码
  2. 创建UsernamePasswordAuthenticationToken对象,认证结果暂时设置为false
  3. 调用getAuthenticationManager()方法获取认证管理器ProviderManager
  4. 调用authenticate()方法

ProviderManager的authenticate()方法中获取所有的AuthenticationProvider实例,遍历看哪个,最终找到AbstractUserDetailsAuthenticationProvider的supports()方法,发现支持UsernamePasswordAuthenticationToken,发现支持后调用AbstractUserDetailsAuthenticationProvider的authenticate()方法,方法中根据用户名查找缓存有没有,没有的话调用retrieveUser()方法,方法中调用

this.getUserDetailsService().loadUserByUsername(username);也就是实现UserDetailsService接口的自定义类loadUserByUsername()方法,获取用户信息和权限信息封装到UserDetails中并返回

继续看AbstractUserDetailsAuthenticationProvider的authenticate()方法,获取完UserDetails信息后进行预检查,看一下用户是否被冻结等等,然后进入DaoAuthenticationProvider的additionalAuthenticationChecks(),这个方法里进行密码的比对,看数据库的密码和表单密码是否一致,默认比对逻辑是BCryptPasswordEncoder的matches()方法完成的

然后是AbstractUserDetailsAuthenticationProvider的postAuthenticationChecks.check(user);进行后置检查,检查账户是否过期等,

然后调用createSuccessAuthentication()方法,创建UsernamePasswordAuthenticationToken对象,构造方法中设置authenticated为true,表示已经通过认证,返回UsernamePasswordAuthenticationToken对象

至此attemptAuthentication()

successfulAuthentication()

AbstractAuthenticationProcessingFilter的successfulAuthentication()方法中把认证信息写入SecurityContextHolder.getContext()中,然后调用AuthenticationSuccessHandler的onAuthenticationSuccess方法,我们可以实现AuthenticationSuccessHandler接口自定义认证成功的处理类

unsuccessfulAuthentication()

失败方法是unsuccessfulAuthentication(),方法中清空SecurityContextHolder保存的信息,调用AuthenticationFailureHandler的onAuthenticationFailure(),我们同样可以实现AuthenticationFailureHandler接口自定义认证失败处理类

授权流程

认证涉及到的过滤器为FilterSecurityInterceptor

  • 调用invoke方法,

    • 进入AbstractSecurityInterceptor的beforeInvocation()方法:

      通过obtainSecurityMetadataSource()获取系统中的权限的配置

      • 进入authenticateIfRequired()方法

        获取Authentication信息,这里面有用户的权限列表,并返回

      • 得到认证信息后调用AccessDecisionManager决策管理器的decide()方法

        方法中获取投票者进行投票

        如果投票不通过的话会抛出AccessDeniedException异常,被ExceptionTranslationFilter处理

总结

我们主要讲了一下SpringSecurity的表单认证流程和授权流程,主要是AbstractAuthenticationProcessingFilter过滤器的作用,我们对AbstractAuthenticationProcessingFilter进行代码分析,涉及过滤器UsernamePasswordAuthenticationFilter,并对其中的方法进行了分析,以及认证成功和认证失败的处理方法successfulAuthentication()和unsuccessfulAuthentication()进行了分析。授权流程主要涉及的是FilterSecurityInterceptor类,通过投票决策器进行投票来判断是否有相应的权限

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
聊聊SpringSecurity的过滤器链的形成 2022-09-21 21:54:11