前言
这篇文章是建立在对SpringSecurity、SpringSecurity OAuth 、OAuth2.0协议、SSO单点登录流程有所了解的基础上,如果这部分不了解的话,源码分析起来就会比较处理,这个流程都稀里糊涂的,这篇文章会从一个未登录授权的请求,从SpringBoot集成的Tomcat一步一步到SpringSecurity再到SpringSecurity OAuth整个授权过程和单点登录的源码流程分析
环境准备
一个完整流程的SSO单点登录项目! 完整项目地址
项目clone下来后项目结构如下
这里建议不要直接使用IDEA打开security文件,推荐将sso-demo打成本地依赖,然后单独将sso-client1、sso-client2、sso-server使用IDEA打开,方便后面源码调试,因为在同一个IDEA中打开设置的断点,三个项目公用的依赖中的代码会重复的执行,跳来跳去,不便于我们调试!
源码分析
这里先发送一个请求,http://127.0.0.1:9992/client1/index.html,然后一路跟着下面断点走
注意:这是NetWork中什么都没有,这个没登录授权的请求,会被下面断点一个一个卡住!1.标记CoyoteAdapter-service
—————————————————————–Tomcat接管请求—————————————————————
这是整个请求到达Tomcat的入口,可以理解为请求的大门!
2.标记invoke()方法
后续还有很多的invoke()方法需要标记,都是底层Tomcat的调用关系实现!
3.标记StandardEngineValve类中invoke()方法
4.标记ErrorReportValve类中invoke()方法
5.标记StandardHostValve类中invoke()方法
6.标记AuthenticatorBase类中invoke()方法
7.标记StandardContextValve类中invoke()方法
8.标记StandardWrapperValve类中invoke()方法
注意断点走到这里后得到filterChain为ApplicationFilterChain对象,然后调用ApplicationFilterChain类中的doFilter()方法
9.标记ApplicationFilterChain类中internalDoFilter()方法
doFilter()方法中的两个断点就可以不用打了,因为会循环调用internalDoFilter()方法
最后选择org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean中的doFilter()方法,这里走到DelegatingFilterProxy类中SpringWeb开始开始接管代码流程
———————————————————–SpringWeb接管请求—————————————————————-
10.标记DelegatingFilterProxy类中doFilter()方法
这里会调用本类中的invokeDelegate()方法,顺带标记一下
得到此时delegate值为FilterChainProxy11.标记FilterChainProxy类中doFilter()方法
进入这里是SpringSecurity已经开始接管请求
———————————————————SpringSecurity接管请求————————————————————
此处调用本类中的doFilterInternal()方法,
在doFilterInternal()方法中又会调用doFilter()方法,注意!!!此处的doFilter()方法不是刚开始的那个doFilter()方法而是下面的
这里又会进入循环
一直会等待值为FilterSecurityInterceptor,这是因为引入了SpringSecurity后才有的,那么这里就可以理解为请求开始正式进入SpringSecurity管控了,已经从Tomcat中脱离出来,开始走SpringSecurity的流程,在之前的文章中也有写过这个FilterSecurityInterceptor拦截器,这个拦截器我们可以理解为是SpringSecurity的大门!12.标记FilterSecurityInterceptor的doFilter()方法
这里会调用本类的invoke()方法
标记invoke()方法
进入beforeInvocation()方法13.标记AbstractSecurityInterceptor类中beforeInvocation()方法
这行代码比较重要
this.accessDecisionManager.decide(authenticated, object, attributes);
1.
在SpringSecurity起到一个决定作用,关系到请求的通过情况!
当然了这里刚开始发送的http://127.0.0.1:9992/client1/index.html这个请求是没有登录授权的,那么在行代码就会报错
14.标记AffirmativeBased类中decide()方法
这里就会抛出异常然后又会被AbstractSecurityInterceptor类中beforeInvocation()方法decide调用处捕获异常,代码如下
然后这里的异常又会抛出
被ExceptionTranslationFilter接收这个类在写SpringSecurity有提到过,是一个SpringSecurity过滤器连上重要的一环
中间蓝色的就是这个异常过滤器!最终会原路返回到CoyoteAdapter中
这里会向浏览器中发送重定向login地址