如何限制同一用户同时登录多台设备?

  最近项目出现新需求,产品经理提出一些用户要限制同一用户同时登录多台设备,一些用户不需要限制,也可以在多台设备上同时登录,想了好久没有太多的思路;后面和同事讨论,才想出了使用 redis 缓存当前用户的登录状态,然后根据已登录用户的状态来限制用户再次登录,为用户分配指定角色,根据角色判断是否限制用户同时登录多台设备,下面我就来将具体的步骤罗列出来;

  大致介绍:项目是采用 Shiro + JWT + Redis 来记录当前用户的登录状态,前端登录时,后端通过校验用户名和密码,通过后生成 JWT 并返回给前端,后续每次请求前端都会携带 token 访问后端,后端校验 token 的有效性,进而操作指定的功能。

  解决方案:用户登录时,Redis 再维护以 username【唯一】作为 key,value = token 的键值对数据,并设置一定的过期时长;创建一个限制用户登录的角色 limit_login ,当获取已登录的用户拥有该角色 limit_login 时,就需要判定用户是否有同时登录其他设备。

业务代码

1)用户登录时,JWT 根据用户名,生成加密 token,并保存在 Redis 缓存中;

// 生成 Token
String token = JwtUtil.sign(sysUser.getUsername(), syspassword);
// 缓存用户登录生成的 token,并设置 key 的过期时间
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);

// 缓存用户登录状态,并设置 key 的过期时间
redisUtil.set(CommonConstant.PREFIX_USER_LOGIN_STATUS + username, token);
redisUtil.expire(CommonConstant.PREFIX_USER_LOGIN_STATUS + username, JwtUtil.EXPIRE_TIME / 1000);

2)限制用户同时登陆需要设置指定角色 limit_login_role,后续再次登录时,需要验证用户是否拥有该角色?验证用户是否限制了同时登陆?

private final String limitLoginRole = "limit_login_role";
// 通过用户名获取用户角色列表
List<String> roleList = sysUserService.getRole(username);
if (roleList.contains(limitLoginRole)) {
    throw new RuntimeException("该用户已登录");  
}

3)用户登录后正常操作系统,需校验 token 有效性,是否过期,校验成功后,刷新 token 和 loginStatus 过期时间

// 从 Redis 中获取 token 数据
String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));
if (StringUtils.isNotEmpty(cacheToken)) {
    // 校验token有效性
    if (JwtUtil.verify(token, userName, passWord)) {
    // 缓存用户登录生成的 token,并设置 key 的过期时间
       redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
       redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);

       // 缓存用户登录状态,并设置 key 的过期时间
       redisUtil.set(CommonConstant.PREFIX_USER_LOGIN_STATUS + username, token);
       redisUtil.expire(CommonConstant.PREFIX_USER_LOGIN_STATUS + username, JwtUtil.EXPIRE_TIME / 1000);
     } 
} 

4)登录登录时,删除 Redis 中的 token 和 loginStatus

String token = request.getHeader(DefContants.X_ACCESS_TOKEN);
//清空用户Token缓存
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + sysUser.getUsername());
//清空用户登录状态缓存
redisUtil.del(CommonConstant.PREFIX_USER_LOGIN_STATUS + sysUser.getUsername());

  以上就是通过 Shiro + JWT + Redis 实现限制用户同时登录的核心代码,不管用户有没有分配限制同时登陆的角色,都会保存一个 loginStatus = token 这样一个键值对,如果用户分配了该角色,就会校验,如果用户没分配该角色,直接走之前的 token 校验即可,忽略限制用户同时登录角色的校验。

 

posted @ 2020-11-03 15:44  菜鸟的奋斗之路  阅读(5769)  评论(0编辑  收藏  举报