spring security 认证及权限控制源码运行流程跟踪

一、认证流程

1、集成过程详情看https://blog.csdn.net/qq_20475615/article/details/100132005

2、首先讲默认配置的流程,我们加了spring security的配置之后,对没有特殊处理的接口发起请求,会跳到默认的登录页

      

  • ① 当请求发起后,会被 UsernamePasswordAuthenticationFilter拦截,实际上幕后主使是它的爸爸AbstractAuthenticationProcessingFilter,它爸爸是掌控这个认证流程的主线

  • ② 接着它儿子 UsernamePasswordAuthenticationFilter开始干活执行attemptAuthentication方法,儿子根据用户输入的账户密码,构建UsernamePasswordAuthenticationToken,然后叫 AuthenticationManager工作

  • ③ AuthenticationManager接口的实现类ProviderManager承担起责任,这里ProviderManager 有对具体使用哪个provider来应战有做判断,后面我们讲自定义provider的时候再说

  • ④ 接着 provider家族的 AbstractUserDetailsAuthenticationProvider和DaoAuthenticationProvider父子兵上阵

  • ⑤ 跟着开始调动UserDetailsService的实现类进行查询用户信息,UserDetailsService是我们集成spring security需实现的

  • ⑥ 查询到相应数据之后,视线转回到步骤④的 provider家族的 AbstractUserDetailsAuthenticationProvider,开始进行校验,它的校验有默认的内部类DefaultPreAuthenticationChecks 和DefaultPostAuthenticationChecks,利用前端用户传入的密码和数据库查询到的密码进行匹配,用户传入的我们已经在前面构建到UsernamePasswordAuthenticationToken 里了

  • ⑦ 至于使用什么密码校验规则,在配置中传入

  • ⑧ 匹配成功后存入权限信息之类的,然后回到幕后主使AbstractAuthenticationProcessingFilter,做相应的后勤工作

  • ⑨ 假设我们在配置类配置了成功登录处理类,则会相应的调用

3、下面讲一下我们自定义filter和provider的流程,就比如最常用的我们微信或授权登录,后台拿到前端传过来的code,我们去获取openid

WxLoginFilter(模仿UsernamePasswordAuthenticationFilter继承AbstractAuthenticationProcessingFilter) 

WxAuthProvider(模仿AbstractUserDetailsAuthenticationProvider实现AuthenticationProvider)

WxAuthenticationToken(模仿UsernamePasswordAuthenticationToken继承AbstractAuthenticationToken)

MiniProgramLoginFilter(模仿UsernamePasswordAuthenticationFilter继承AbstractAuthenticationProcessingFilter)

MiniProgramAuthProvider(模仿AbstractUserDetailsAuthenticationProvider实现AuthenticationProvider)

MiniProgramAuthenticationToken(模仿UsernamePasswordAuthenticationToken继承AbstractAuthenticationToken)

修改配置类SecurityConfig

  • ② 那跟上面默认配置的差别在哪里了,它是怎么自动匹配我们的请求呢,用postman请求授权接口http://127.0.0.1:8090/mini/auth,这个其实就是我们配置在自定义的MiniProgramLoginFilter里,幕后主使AbstractAuthenticationProcessingFilter操控着这一切,对url进行匹配,调用最适合的儿子来处理请求

  • ③ 前面说了儿子干活执行attemptAuthentication方法,那儿子构建好token之后调用AuthenticationManager接口的实现类ProviderManager,这里ProviderManager 怎么知道来调用我们自定义的哪个provider呢?
  • 主要靠provider.supports,它根据我们在filter那里传入的token类型,匹配provider实现类中supports校验的类型,一致则可以调用

  • 至于其他的流程也就跟上面的没两样啦

4、总结认证流程:filter->AuthenticationManager->provider->UserDetailService->provider->filter

  1. 如果自定义了filter则根据匹配进去相应的filter,当然入口还是父类 AbstractAuthenticationProcessingFilter 的doFilter,这里的 !this.requiresAuthentication(request, response) 则是对多个自定义filter进行请求匹配
  2. 接着到AuthenticationManager接口的实现类ProviderManager,具体选择对应 AuthenticationProvider的实现,默认是DaoAuthenticationProvider,判断是用 provider.supports(),每个自定义provider都会继承supports,根据信息token类(如UsernamePasswordAuthenticationToken)和在filter传进来的类型行判断
  3. DaoAuthenticationProvider中的retrieveUser开始查数据库验证,查到之后就回去它的爸爸AbstractUserDetailsAuthenticationProvider开始check,最主要还是这个this.additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken)authentication)
  4. 最后校验成功,this.createSuccessAuthentication(principalToReturn, authentication, user)返回,里面还有对权限的初始化
  5. 上面步骤3和步骤4不是必须的,假如自己自定义了 provider,比如写了微信登录之类的,那就不需要数据库验证的过程,这时候没有步骤3和4
  6. 最后的最后,返回到初始层,AbstractAuthenticationProcessingFilter中,接着将登录信息放入session还有上下文,this.successfulAuthentication(request, response, chain, authResult)根据是否自定义了SuccessHandler或者FailHandler来调用

二、权限控制

1、权限流程

  • ① 加入权限控制,增加三个类

MyAccessDecisionManager(实现AccessDecisionManager) 

MyFilterSecurityInterceptor(继承AbstractSecurityInterceptor)

SecurityMetadataSource(实现FilterInvocationSecurityMetadataSource)

修改配置类SecurityConfig

  • ② 当请求被MyFilterSecurityInterceptor拦截后,调用父类AbstractSecurityInterceptor的beforeInvocation方法

  • ③ 根据子类注入的 SecurityMetadataSource实现类进行处理

  • ④ 查询到相应的系统权限,返回给AbstractSecurityInterceptor

  • ⑤ 接着调用accessDecisionManager开始进行匹配, accessDecisionManager我们开始就已经注入

  • ⑥ 匹配用户拥有的权限和用户的请求,如果包含则可以访问,否则不行

2、权限控制总结:

  1. 自定义的filter并注入AccessDecisionManager的实现类,接着调用filter的父类AbstractSecurityInterceptor中的 beforeInvocation 进行操作
  2. 先获取FilterInvocationSecurityMetadataSource的实现类中的 getAttributes 方法获取数据库中的权限列表,返回用户请求的
  3. 接着调用 AccessDecisionManager 的实现类中的 decide 方法用上下文中用户的权限和用户请求的进行匹配,达到权限控制的目的

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章