案例代码
ChaiRongD/Demooo - Gitee.com
源码分析
初始化
我们从WebSecurityConfiguration类的加载开始,因为这个类带有@Configuration,从这里出发也说的过去。这个类有一个带有@Autowired的方法,所以在Bean的生命周期的里会执行这个方法,执行这个方法的时候会执行this.webSecurity=xxx ,创建webSecurity。
然后创建SpringSecurityFilterChain对象,并且name 等于常量 "springSecurityFilterChain"
其中springSecurityFilterChain的类型是FilterChainProxy,里面有一个类型是DefaultSecurityChain属性filterChains,filterChains里包含11个默认的Filter。
登陆验证过程
在浏览器中输入http://localhost:8080/login (这个地址是/login是配置的),跳转到登陆页面;输入正确的用户名(zhangsan)和密码(123456)后,我们看这个请求的执行流程。
我们从DelegatingFilterProxy.doFilter()开始,首先获取applicationContext,然后从applicationContext中获取DefalutSecurityFilterChain(包含11个Filter)
把11个Security Filter 和FilterChain 封装成VirtualFilterChain,执行VirtualFilterChain.doFilter()方法
获取SecurityContext对象。session存在并且session.getAttribute("SPRING_SECURITY_CONTEXT")!=null,返回SecurityContxt;
否则创建一个新的SecurityContext。
并且把SecurityContext放在SecurityContextHolder(ThreadLocal)中。
AbstractAuthenticationProcessingFilter.doFilter()方法里面做了认证,并且有认证成功后的 自定义处理逻辑
认证成功后。把认证成功的信息保存在session中
获取用户信息
@RequestMapping("/hello") @ResponseBody public String hello(Authentication authentication) { System.out.println(authentication.getName()); return "hello security"; } @RequestMapping("/hello2") @ResponseBody public String hello2(Authentication authentication) { String username = SecurityContextHolder.getContext().getAuthentication().getName(); return "hello security2"; }
我们可以在controller层获取,也可以在SecurityContextHolder(ThreadLocal)中获取。
为什么可以在 SecurityContextHolder中获取,因为每次请求都会在session中获取认证信息,并且保存在ThreadLocal中。
拓展
request.getSession(true/false)的区别
HttpServletRequest.getSession(ture)等同于 HttpServletRequest.getSession()
HttpServletRequest.getSession(ture)表示如果有session返回,没有创建一个返回
HttpServletRequest.getSession(false)表示如果有session返回,没有就为null;