如何限制同一用户同时登录多台设备?
最近项目出现新需求,产品经理提出一些用户要限制同一用户同时登录多台设备,一些用户不需要限制,也可以在多台设备上同时登录,想了好久没有太多的思路;后面和同事讨论,才想出了使用 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 校验即可,忽略限制用户同时登录角色的校验。