SecurityContextHolder简介说明

欣喜 SpringSecurity 发布时间:2024-11-28 10:58:07 阅读数:6251 1
下文笔者讲述Spring Security中SecurityContextHolder简介说明,如下所示

SecurityContextHolder简介

 
SecurityContextHolder是SpringSecurity最基础组件
   用于存放SecurityContext对象
   默认使用ThreadLocal实现
   保证本线程内所有的方法都可以获得SecurityContext对象
   
SecurityContextHolder 有其他两种模式
   分别SecurityContextHolder.MODE_GLOBAL 和 SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
       SecurityContextHolder.MODE_GLOBAL表示SecurityContextHolder对象的全局的,应用中所有线程都可以访问
	   SecurityContextHolder.MODE_INHERITABLETHREADLOCAL用于线程有父子关系的情境中,线程希望自己的子线程和自己有相同的安全性
// 获取安全上下文对象 ,此处同Shiro一样保存在ThreadLocal中
//如果不存在,则创建一个authentication属性为null的empty安全上下文对象
SecurityContext securityContext = SecurityContextHolder.getContext();

// 获取当前认证principal(当事人),或request token (令牌)
// 如果没有认证,会是 null,该例子是认证之后的情况
Authentication authentication = securityContext.getAuthentication()

//获取当事人信息对象,返回结果是Object类型
//实际上可以是应用程序自定义带有更多应用相关信息的某个类型

//该对象是 Spring Security 核心接口 UserDetails一个实现类
//数据库中保存一个用户信息到SecurityContextHolder中Spring Security需要的用户信息格式
// 一个适配器。
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
	String username = ((UserDetails)principal).getUsername();
} else {
	String username = principal.toString();
}

修改SecurityContextHolder的工作模式
 综上所述,SecurityContextHolder可以工作在以下三种模式之一:
 1.MODE_THREADLOCAL(缺省工作模式)
 2.MODE_GLOBAL
 3.MODE_INHERITABLETHREADLOCAL
 4.修改SecurityContextHolder的工作模式有两种方法
		 a:设置一个系统属性(system.properties):spring.security.strategy;
			  SecurityContextHolder会自动从该系统属性中尝试获取被设定的工作模式
		 b:调用SecurityContextHolder静态方法setStrategyName()
		      程序化方式主动设置工作模式的方法     

SecurityContextHolder存储SecurityContext的方式(默认就是mode_threadlocal)
 1.单机系统
     即应用从开启到关闭的整个生命周期只有一个用户在使用
	    由于整个应用只需要保存一个SecurityContext(安全上下文即可)
 2.多用户系统
      如Web系统
	    整个生命周期可能同时有多个用户在使用
		   这时候应用需要保存多个SecurityContext(安全上下文)
		    需要利用ThreadLocal进行保存
			 每个线程都可以利用ThreadLocal
			   获取其自己SecurityContext,及安全上下文。

如
  使用jwt实现登录功能时候
  可将用户信息保存在安全上下文中

 @Override
	public String login(String username, String password) {
		String token = null;
		//密码需要客户端加密后传递
		try {
			UserDetails userDetails = loadUserByUsername(username);
			if(!password.equals(BasicEncryptUtils.decryptByRSA(userDetails.getPassword()))){
				throw new ServiceException("password.is.not.correct", ResultCode.VALIDATE_FAILED.getCode());
			}
			//根据userDetails构建新的Authentication
			UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
			//存放authentication到SecurityContextHolder
			SecurityContextHolder.getContext().setAuthentication(authentication);
			//使用jwt生成token
			token = jwtTokenUtil.generateToken(userDetails, RsaUtils.getPrivateKey(propertiesUtils.getPrivateKeyUrl()));
			//到redis中查看该账号是否之前已经登录
			if (redisUtil.getValueByKey(CommonConstant.ormis_online_login_user_info+username)!=null){
				//删掉对应的数据
				redisUtil.deleteCache(CommonConstant.ormis_online_login_user_info+username);
			}
			//重新存储
			redisUtil.set(CommonConstant.ormis_online_login_user_info+username,token,propertiesUtils.getExpiration());
		} catch (Exception e) {
			log.error("login error is {}", e.getMessage());
			throw new ServiceException(e.getMessage(), ResultCode.VALIDATE_FAILED.getCode());
		}
		return token;
	}
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaFramework/SpringSecurity/202411/8193.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者