项目中使用shrio,如何获取当前用户信息

33、项目中使用shrio,如何获取当前用户信息

原理:直接从当前线程里面拿到subject,前台每一次请求的话,都是要走拦截器的,根据前台传回的cookie,通过shrio的 SessionManager 去获取到对应的seesionid,然后再绑定到线程上,即每个shiro拦截到的请求之后,重新获取到seesionid, 然后根据seesionid创建Subject,清除当前线程的绑定,然后重新绑定的线程中,之后执行过滤器。所以我们再SecurityUtils.getSubject()中获取的一直是当前用户的信息。

使用shiro时,如果正常登陆(执行subject.login(token)成功)就能在全局通过SecurityUtils.getSubject().getPrincipal()获取用户信息。

LoginUser userNow=(LoginUser) SecurityUtils.getSubject().getPrincipal();

返回的是Loginuser 是因为我们在登录的时候,已经设置了

/**
    * 用户信息认证是在用户进行登录的时候进行验证(不存redis)
 * 也就是说验证用户输入的账号和密码是否正确,错误抛出异常
 *
 * @param auth 用户登录的账号密码信息
 * @return 返回封装了用户信息的 AuthenticationInfo 实例
    * @throws AuthenticationException
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
   String token = (String) auth.getCredentials();
   if (token == null) {
      log.info("————————身份认证失败——————————IP地址:  "+ ObjectConvertUtils.getIpAddrByRequest(SpringContextUtils.getHttpServletRequest()));
      throw new AuthenticationException("token为空!");
   }
   // 校验token有效性
   LoginUser loginUser = this.checkUserTokenIsEffect(token);
   return new SimpleAuthenticationInfo(loginUser, token, getName());
}

/**
 * 校验token的有效性
 *
 * @param token
 */
public LoginUser checkUserTokenIsEffect(String token) throws AuthenticationException {
   // 解密获得username,用于和数据库进行对比
   String username = JwtUtil.getUsername(token);
   if (username == null) {
      throw new AuthenticationException("token非法无效!");
   }

   // 查询用户信息
   log.info("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
       LoginUser loginUser = sysBaseAPI.getUserByName(username);
   if (loginUser == null) {
      throw new AuthenticationException("用户不存在!");
   }
       // 判断用户状态
       if (loginUser.getStatus().equals(CommonConstant.USER_FREEZE.toString())) {
           throw new AuthenticationException("账号已被锁定,请联系管理员!");
       }
   // 校验token是否超时失效 & 或者账号密码是否错误
   if (!jwtTokenRefresh(token, username, loginUser.getPassword())) {
      throw new AuthenticationException("Token失效,请重新登录!");
   }

   return loginUser;
}

/**
 * JWTToken刷新生命周期 (实现: 用户在线操作不掉线功能)
 * 1、登录成功后将用户的JWT生成的Token作为k、v存储到cache缓存里面(这时候k、v值一样),缓存有效期设置为Jwt有效时间的2倍
 * 2、当该用户再次请求时,通过JWTFilter层层校验之后会进入到doGetAuthenticationInfo进行身份验证
 * 3、当该用户这次请求jwt生成的token值已经超时,但该token对应cache中的k还是存在,则表示该用户一直在操作只是JWT的token失效了,程序会给token对应的k映射的v值重新生成JWTToken并覆盖v值,该缓存生命周期重新计算
 * 4、当该用户这次请求jwt在生成的token值已经超时,并在cache中不存在对应的k,则表示该用户账户空闲超时,返回用户信息已失效,请重新登录。
 * 注意: 前端请求Header中设置Authorization保持不变,校验有效性以缓存中的token为准。
    *       用户过期时间 = Jwt有效时间 * 2。
 *
 * @param userName
 * @param passWord
 * @return
 */
public boolean jwtTokenRefresh(String token, String userName, String passWord) {
   String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));
   if (ObjectConvertUtils.isNotEmpty(cacheToken)) {
      // 校验token有效性
      if (!JwtUtil.verify(cacheToken, userName, passWord)) {
         String newAuthorization = JwtUtil.sign(userName, passWord);
         // 设置超时时间
         redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization);
         redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME *2 / 1000);
               log.info("——————————用户在线操作,更新token保证不掉线—————————jwtTokenRefresh——————— "+ token);
      }
      return true;
   }
   return false;
}
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Shiro实现接口授权的具体实现步骤如下: 1. 引入Shiro和Spring-boot-starter依赖: ```xml <dependencies> <!-- Shiro依赖 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.8.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.8.0</version> </dependency> <!-- Spring-boot-starter依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> ``` 2. 配置Shiro的Filter和Realm: ```java @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean(); filterFactoryBean.setSecurityManager(securityManager); filterFactoryBean.setLoginUrl("/login"); // 设置未登录时跳转的URL filterFactoryBean.setUnauthorizedUrl("/unauthorized"); // 设置未授权时跳转的URL // 配置拦截规则 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/login", "anon"); // 登录接口放行 filterChainDefinitionMap.put("/logout", "logout"); // 注销接口放行 filterChainDefinitionMap.put("/**", "authc"); // 其他接口全部拦截,需要认证后访问 filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return filterFactoryBean; } @Bean public DefaultWebSecurityManager securityManager(Realm realm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm); return securityManager; } @Bean public Realm realm() { // 自定义Realm实现 return new MyRealm(); } } ``` 3. 自定义Realm实现授权逻辑: ```java public class MyRealm extends AuthorizingRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 获取当前用户信息 String username = (String) principals.getPrimaryPrincipal(); // 查询用户角色和权限信息 Set<String> roles = new HashSet<>(); Set<String> permissions = new HashSet<>(); // TODO: 查询用户角色和权限信息 // roles.add("admin"); // permissions.add("user:list"); // 封装角色和权限信息 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 获取用户输入的用户名和密码 String username = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); // TODO: 验证用户名和密码是否正确 // if (!"admin".equals(username)) { // throw new UnknownAccountException("用户名不存在!"); // } // if (!"admin".equals(password)) { // throw new IncorrectCredentialsException("密码错误!"); // } // 封装用户认证信息 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password, getName()); return authenticationInfo; } } ``` 4. 在Controller使用注解实现接口授权: ```java @RestController @RequestMapping("/user") public class UserController { @RequiresPermissions("user:list") @GetMapping("/list") public String list() { return "用户列表"; } @RequiresPermissions("user:add") @PostMapping("/add") public String add() { return "添加用户"; } } ``` 在Controller方法上使用@RequiresPermissions注解,指定需要的权限,如果当前用户没有该权限,则会抛出AuthorizationException异常,可以在异常处理器统一处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值