SecurityContextHolder简介说明
下文笔者讲述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; }
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。