通过使用SecurityContextHolder就可以得到SecurityContext对象了,可以直接使用SecurityContext对象来获取当前的认证信息
@RequestMapping("/index")
public String index(){
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
User user = (User) authentication.getPrincipal();
System.out.println(user.getUsername());
System.out.println(user.getAuthorities());
return "index";
}
通过SecurityContext我们就可以快速获取当前用户的名称和授权信息
还可以直接从Session中获取SecurityContext
@RequestMapping("/index")
public String index(@SessionAttribute("SPRING_SECURITY_CONTEXT") SecurityContext context){
Authentication authentication = context.getAuthentication();
User user = (User) authentication.getPrincipal();
System.out.println(user.getUsername());
System.out.println(user.getAuthorities());
return "index";
}
SecurityContextHolder是有一定的存储策略的,SecurityContextHolder中的SecurityContext对象会在一开始请求到来时被设定,至于存储方式其实是由存储策略决定的。如果创建一个子线程去获取是无法获取到认证信息的
@RequestMapping("/index")
public String index(){
new Thread(() -> { //创建一个子线程去获取
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
User user = (User) authentication.getPrincipal(); //NPE
System.out.println(user.getUsername());
System.out.println(user.getAuthorities());
});
return "index";
}
SecurityContextHolder的存储策略默认是`MODE_THREADLOCAL`,它是基于ThreadLocal实现的,`getContext()`方法本质上调用的是对应的存储策略实现的方法
SecurityContextHolderStrategy有三个实现类
* GlobalSecurityContextHolderStrategy:全局模式,不常用
* ThreadLocalSecurityContextHolderStrategy:基于ThreadLocal实现,线程内可见
* InheritableThreadLocalSecurityContextHolderStrategy:基于InheritableThreadLocal实现,线程和子线程可见
如果需要在子线程中获取,那么需要修改SecurityContextHolder的存储策略,在初始化的时候设置
- @PostConstruct
- public void init(){
- SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
- }
SecurityContext的生命周期:请求到来时从Session中取出,放入SecurityContextHolder中,请求结束时从SecurityContextHolder取出,并放到Session中,实际上就是依靠Session来存储的,一旦会话过期验证信息也跟着消失。