如何限制同一用户同时登录多台设备?
最近项目出现新需求,产品经理提出一些用户要限制同一用户同时登录多台设备,一些用户不需要限制,也可以在多台设备上同时登录,想了好久没有太多的思路;后面和同事讨论,才想出了使用 redis 缓存当前用户的登录状态,然后根据已登录用户的状态来限制用户再次登录,为用户分配指定角色,根据角色判断是否限制用户同时登录多台设备,下面我就来将具体的步骤罗列出来;
大致介绍:项目是采用 Shiro + JWT + Redis 来记录当前用户的登录状态,前端登录时,后端通过校验用户名和密码,通过后生成 JWT 并返回给前端,后续每次请求前端都会携带 token 访问后端,后端校验 token 的有效性,进而操作指定的功能。
解决方案:用户登录时,Redis 再维护以 username【唯一】作为 key,value = token 的键值对数据,并设置一定的过期时长;创建一个限制用户登录的角色 limit_login ,当获取已登录的用户拥有该角色 limit_login 时,就需要判定用户是否有同时登录其他设备。
业务代码
1)用户登录时,JWT 根据用户名,生成加密 token,并保存在 Redis 缓存中;
1 2 3 4 5 6 7 8 9 | // 生成 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,后续再次登录时,需要验证用户是否拥有该角色?验证用户是否限制了同时登陆?
1 2 3 4 5 6 | private final String limitLoginRole = "limit_login_role" ; // 通过用户名获取用户角色列表 List<String> roleList = sysUserService.getRole(username); if (roleList.contains(limitLoginRole)) { throw new RuntimeException( "该用户已登录" ); } |
3)用户登录后正常操作系统,需校验 token 有效性,是否过期,校验成功后,刷新 token 和 loginStatus 过期时间
1 2 3 4 5 6 7 8 9 10 11 | // 从 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 ); } <br>} |
4)登录登录时,删除 Redis 中的 token 和 loginStatus
1 2 3 4 5 | 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 校验即可,忽略限制用户同时登录角色的校验。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架