今日内容

  • ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼

    ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨


学习目标

  • ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽

    ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇

    ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨


一、前后端分离版本解决方案

1.application.yml 添加相关配置

用于灵活控制单个账号多设备登录的情况

#token配置
token: # 这个是若依框架本身存在的配置 
	# 是否允许并多设备登录   true:允许  false:不允许  这个是新增的配置
    singleLogin: false

2.CacheConstants 类中新增常量

/**
 * 登录用户id redis key 用于实现灵活控制多设备登录
 */
public static final String LOGIN_USER_ID_KEY = "login_user_ids:";

3.TokenService 类中新增相关代码

3.1 头部添加获取我们上面新增的配置

// 是否允许多设备登录
@Value("${token.singleLogin}")
private boolean singleLogin;

3.2 在尾部添加涉及本次控制并发登录所需要的redis key组成

/**
 * 获取用户Key
 *
 * @param userId 当前登录用户的主键id
 * @return
 */
private String getUserKey(Long userId) {
    return CacheConstants.LOGIN_USER_ID_KEY + userId;
}

3.3 在refreshToken方法中做代码调整

主要原因:在这里做主要是保证后续如果由多种登录方式 手机验证码等 可以兼容(只要都调用了createToken方法去创建token令牌)

源代码:

/**
 * 刷新令牌有效期
 *
 * @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());
    redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}

改造后:

/**
 * 刷新令牌有效期
 *
 * @param loginUser 登录信息
 */
public void refreshToken(LoginUser loginUser) {
    // 判断是否允许多端登录, 如果不允许则删除
    if (!singleLogin) {
        String userIdKey = getUserKey(loginUser.getUserId());
        String userKey = redisCache.getCacheObject(userIdKey);
        if (StringUtils.isNotEmpty(userKey)) {
            redisCache.deleteObject(userIdKey);
            redisCache.deleteObject(userKey);
        }
    }
    loginUser.setLoginTime(System.currentTimeMillis());
    loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
    // 根据uuid将loginUser缓存
    String userKey = getTokenKey(loginUser.getToken());
    redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    // 判断是否允许多端登录, 如果不允许, 则记录用户IdKey对应的用户信息Key
    if (!singleLogin) {
        String userIdKey = getUserKey(loginUser.getUserId());
        redisCache.setCacheObject(userIdKey, userKey, expireTime, TimeUnit.MINUTES);
    }
}

3.4 对delLoginUser做代码新增

这个方法用于手动退出时 删除对应的token以及我们本次维护的redis key,也就是后续对LogoutSuccessHandlerImpl类做调整的一部分

源代码:

/**
 * 删除用户身份信息
 */
public void delLoginUser(String token) {
    if (StringUtils.isNotEmpty(token)) {
        String userKey = getTokenKey(token);
        redisCache.deleteObject(userKey);
    }
}

改造后:

/**
 * 删除用户身份信息
 */
public void delLoginUser(String token, Long userId) {
    if (StringUtils.isNotEmpty(token)) {
        String userKey = getTokenKey(token);
        redisCache.deleteObject(userKey);
    }
    if (StringUtils.isNotEmpty(userId)) {
        String userIdKey = getUserKey(userId);
        redisCache.deleteObject(userIdKey);
    }
}

3.5 新增用于强制推出方法

用于后续SysUserOnlineController类强制退出接口代码做相关调整,在前端的监控-在线用户界面做强退操作

/**
 * 强制退出
 *
 * @param tokenId   token(uuid)
 */
public void forceLogout(String tokenId){
    String userKey = getTokenKey(tokenId);
    if(!singleLogin){//多设备登录相关控制代码
        LoginUser loginUser = redisCache.getCacheObject(userKey);
        String userId = loginUser.getUserId();
        String userIdKey = getUserKey(userId);
        redisCache.deleteObject(userIdKey);
    }
    redisCache.deleteObject(userKey);
}

4.自定义退出处理类LogoutSuccessHandlerImpl 做调整

源代码:

tokenService.delLoginUser(loginUser.getToken());

改造后:

tokenService.delLoginUser(loginUser.getToken(), loginUser.getUserId());

5.在线用户监控接口类SysUserOnlineController 做相关调整

5.1 头部引入TokenService

注意引包时,引入项目的,而不是Security包的

import com.ruoyi.framework.web.service.TokenService;

@Autowired
private TokenService tokenService;

5.2 强退方法forceLogout调整

源代码:

/**
 * 强退用户
 */
public AjaxResult forceLogout(@PathVariable String tokenId) {
    redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
    return AjaxResult.success();
}

改造后:

/**
 * 强退用户
 */
public AjaxResult forceLogout(@PathVariable String tokenId) {
    tokenService.forceLogout(tokenId);
    return AjaxResult.success();
}
Logo

快速构建 Web 应用程序

更多推荐