ruoyi官网:如何限制账户不允许多终端登录
吐槽:官网写的不够全面,和原生的代码改动有冲突。
以下是成功设置的样例,同一个账号多次登录时,后面登录的人会把前面的登录过的顶掉。
分离版springboot+vue
1、application.yml新增一个配置soloLogin用于限制多终端同时登录。
修改token的配置
# token配置
token:
# 是否允许账户多终端同时登录(true允许 false不允许)
soloLogin: false
# 令牌自定义标识
header: Authorization
...省略
2、Constants.java新增一个常量LOGIN_USERID_KEY公用
Constants.java 的路径是 package com.ruoyi.common.constant;
/**
* 登录用户编号 redis key
*/
public static final String LOGIN_USERID_KEY = "login_userid:";
3、调整TokenService.java,存储&刷新缓存用户编号信息
下面两个方法实际上已经有了,需要替换掉。
// 是否允许账户多终端同时登录(true允许 false不允许)
@Value("${token.soloLogin}")
private boolean soloLogin;
/**
* 删除用户身份信息
*/
public void delLoginUser(String token, Long userId)
{
if (StringUtils.isNotEmpty(token))
{
String userKey = getTokenKey(token);
redisCache.deleteObject(userKey);
}
if (!soloLogin && StringUtils.isNotNull(userId))
{
String userIdKey = getUserIdKey(userId);
redisCache.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());
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
if (!soloLogin)
{
// 缓存用户唯一标识,防止同一帐号,同时登录
String userIdKey = getUserIdKey(loginUser.getUser().getUserId());
redisCache.setCacheObject(userIdKey, userKey, expireTime, TimeUnit.MINUTES);
}
return userKey;
}
private String getUserIdKey(Long userId)
{
return Constants.LOGIN_USERID_KEY + userId;
}
4、自定义退出处理类LogoutSuccessHandlerImpl.java清除缓存方法添加用户编号
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException
{
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser))
{
String userName = loginUser.getUsername();
// 删除用户缓存记录(旧方法)
//tokenService.delLoginUser(loginUser.getToken());
// 删除用户缓存记录 只允许单用户登录(关键)
tokenService.delLoginUser(loginUser.getToken(), loginUser.getUser().getUserId());
// 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
}
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success("退出成功")));
}
5、登录方法SysLoginService.java,验证如果用户不允许多终端同时登录,清除缓存信息
修改的是login()这个方法
recordLoginInfo(loginUser.getUserId());
//在上面这句代码后面新增,以下是新增的部分
if (!soloLogin)
{
// 如果用户不允许多终端同时登录,清除缓存信息
String userIdKey = Constants.LOGIN_USERID_KEY + loginUser.getUser().getUserId();
String userKey = redisCache.getCacheObject(userIdKey);
if (StringUtils.isNotEmpty(userKey))
{
redisCache.deleteObject(userIdKey);
redisCache.deleteObject(userKey);
}
}