RuoYi框架 限制账户不允许多终端登录
一、需求
- 在管理系统中,一般情况一个账号是可以多客户端进行登录。但是这样可能造成安全隐患,当同一账号的多端同时操作同一业务时,有可能造成数据混肴的后果。那么就需要同一时间一个账号只能一个地方登录。另一端登录,则原先登录的客户端则会失效。
二、解决原理
- 登录后获取的用户ID和token存入redis中,以用户ID为key,token为value的格式存入。注销时,则从redis中删除。当第二个人登录时,如果发现redis中已经存在该用户对应的key,则说明该账号已经登录,则将登录生成的token覆盖原token,从而使之前登录的客户端失效。限制账户不允许多终端登录。
三、实例代码
RuoYi官网实例
- 1.application.yml新增一个配置soloLogin用于限制是否启用多终端同时登录。
token:
# 是否允许账户多终端同时登录(true允许 false不允许)
soloLogin: false
- 2.Constants.java(已存在的JAVA类)新增一个常量LOGIN_USERID_KEY公用。
/**
* 登录用户编号 redis key
* 加上独特的前缀,避免重复的key
*/
public static final String LOGIN_USERID_KEY = "login_userid:";
- 3.调整TokenService.java(已存在的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);
}
/* 添加的部分
* 删除身份信息的同时,将redis中的缓存同时删除
*/
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());
// 刷新缓存中的token
redisCache.setCacheObject(userIdKey, userKey, expireTime, TimeUnit.MINUTES);
}
}
// 处理key,userId添加前缀,避免key重复
private String getUserIdKey(Long userId){
return Constants.LOGIN_USERID_KEY + userId;
}
- 4.自定义退出处理类LogoutSuccessHandlerImpl.java(登出函数所在的类)清除缓存方法添加用户编号
/*
* 删除用户缓存记录
* 登出会话的方法中,删除redis缓存
*/
public void logout(){
tokenService.delLoginUser(loginUser.getToken(), loginUser.getUser().getUserId());
}
- 5.登录方法SysLoginService.java(已存在的JAVA类),验证如果用户不允许多终端同时登录,清除缓存信息
// 是否允许账户多终端同时登录(true允许 false不允许)
@Value("${token.soloLogin}")
private boolean soloLogin;
public LoginUser login(String username, String password){
// 原代码块
......
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);
}
}
}