一. 前言

目前框架用的是RuoYi-Cloud版本:https://github.com/yangzongzhuan/RuoYi-Cloud
业务需求:同一个账户只能在一个地方登陆,后登录的账号挤掉之前登陆的账号

二. 参考

参考了若依分离版,后面有改动 如何限制账户不允许多终端登录 https://doc.ruoyi.vip/ruoyi-vue/other/faq.html#%E5%A6%82%E4%BD%95%E9%99%90%E5%88%B6%E8%B4%A6%E6%88%B7%E4%B8%8D%E5%85%81%E8%AE%B8%E5%A4%9A%E7%BB%88%E7%AB%AF%E7%99%BB%E5%BD%95

三. 代码实现

三.一 在ruoyi-auth模块下的bootstrap.yml文件下新增一个配置soloLogin用于限制多终端同时登录。

# token配置
token:
  # 是否允许账户多终端同时登录(true允许 false不允许)
  soloLogin: false

如图:在这里插入图片描述
ruoyi-system模块下的bootstrap.yml也同样加上

三.二 我是在CacheConstants.java下添加用户缓存的常量

 /**
     * 登录用户编号 redis key
     */
    public static final String LOGIN_USERID_KEY = "login_userid:";

三.三 修改 TokenService.java类下的方法

    /**
     * 是否允许账户多终端同时登录(true允许 false不允许)
     */
    @Value("${token.soloLogin}")
    private boolean soloLogin;

修改方法:


  /**
     * 删除用户缓存信息
     */
    public void delLoginUser(String token, Long userId) {
        if (StringUtils.isNotEmpty(token)) {
            String userkey = JwtUtils.getUserKey(token);
            redisService.deleteObject(getTokenKey(userkey));
        }
        if (!soloLogin && StringUtils.isNotNull(userId)) {
            String userIdKey = getUserIdKey(userId);
            redisService.deleteObject(userIdKey);
        }
    }
    /**
    
     * 刷新令牌有效期
     *
     * @param loginUser 登录信息
     */
  public void refreshToken(LoginUser loginUser) {
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
        // 根据uuid将loginUser缓存
        String userKey = getTokenKey(loginUser.getToken());
        redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
        if (!soloLogin)
        {
            // 缓存用户唯一标识,防止同一帐号,同时登录
            String userIdKey = getUserIdKey(loginUser.getSysUser().getUserId());
            redisService.setCacheObject(userIdKey, userKey, expireTime, TimeUnit.MINUTES);
        }
    }

    private String getTokenKey(String token) {
        return ACCESS_TOKEN + token;
    }

    private String getUserIdKey(Long userId)
    {
        return CacheConstants.LOGIN_USERID_KEY + userId;
    }

三.四 修改登录方法SysLoginService.java,验证如果用户不允许多终端同时登录,清除缓存信息

 /**
     * 是否允许账户多终端同时登录(true允许 false不允许)
     */
    @Value("${token.soloLogin}")
    private boolean soloLogin;

    /**
     * 登录
     */
    public LoginUser login(String username, String password)
    {
      ==================前面的代码============
        LoginUser userInfo = userResult.getData();
        SysUser user = userResult.getData().getSysUser();
      ==================我在这里加判断的 新增的代码============
        if (!soloLogin)
        {
            // 如果用户不允许多终端同时登录,清除缓存信息
            String userIdKey = CacheConstants.LOGIN_USERID_KEY + user.getUserId();
            String userKey = redisService.getCacheObject(userIdKey);
            if (StringUtils.isNotEmpty(userKey))
            {
                redisService.deleteObject(userIdKey);
                redisService.deleteObject(userKey);
            }
        }
       ===============后面的代码===========
        return userInfo;
    }

三.五 修改AuthLogic.java中会话注销方法

  /**
     * 会话注销,根据指定Token
     */
    public void logoutByToken(String token)
    {
        LoginUser loginUser = getLoginUser(token);
        if(loginUser!=null){
            tokenService.delLoginUser(token,loginUser.getUserid());
        }else{
            tokenService.delLoginUser(token,null);
        }
    }

这里是用户注销的时候调用的。

四. 总结

思路就是:修改redis登录的key,目前的key只存放了token,修改为userid(id为唯一) + key的方式去判断,登录前判断redis中当前登录用户是否已经登录,如果已经登录删除已经存在的token和userId。

Logo

快速构建 Web 应用程序

更多推荐