01.项目场景:
简述项目相关背景:
系统需要能够通过数据字典的开关来实现单用户登录
02.问题描述
描述项目中遇到的问题:
一开始的思路是在用户第一次登录发起请求时,通过key来获取token,与请求头中的token对比,若相同则说明没有第二次登录,若不同则说明有第二次登录,第一次登录的就需要下线
但是发现redis中保存token的key是前缀+token的形式,因此就没办法拿到key
03.解决方案:
该问题的具体解决方案:
因为单用户登录时,它的username是相同的,所以整体思路就是遍历redis中的token,然后根据token获取username,将之与正在登录的用户的username做对比 若相同再加上对数据字典的单用户登录是否启用的判断,来执行后面的操作
Result<JSONObject> result = new Result<JSONObject>();
//根据前缀tokenFlag查询出redis中token
Set<String> keys = redisTemplate.keys(CommonConstant.TOKEN_FLAG+ "*");
String redisToken;
String redisUsername;
//查询系统字典中的loginRestrict的字典项
SysDict sysDict = sysDictService.getOne(new LambdaQueryWrapper<SysDict>()
.eq(SysDict::getDictCode,CommonConstant.LOGIN));
//多端登录后者挤掉前者
String afterCanStatus = null;
//多端登录后者不可登录
String afterNotStatus = null;
if (ObjectUtil.isNotNull(sysDict)) {
//通过字典编码查询字典项纪录集合
List<SysDictItem> sysDictItemList = sysDictItemService.getItemsByDictCode(sysDict.getDictCode());
for (SysDictItem sysDictItem : sysDictItemList) {
if (CommonConstant.LOGIN_RESTRICT_001.equals(sysDictItem.getItemValue())) {
//后者挤掉前者标识
afterCanStatus = sysDictItem.getStatus();
} else {
//后者不能登录标识
afterNotStatus = sysDictItem.getStatus();
}
}
//遍历key取username
for (String key : keys) {
redisToken = key.substring(18);
//取redis中的username
redisUsername = JwtUtil.getUsername(redisToken);
//与当前登录用户的username作比对,有相同的并且数据字典为后者强制前者下线则把redis中的key删除
if (username.equals(redisUsername) && CommonConstant.STATUS_1.equals(afterCanStatus)) {
redisTemplate.delete(key);
} else if (username.equals(redisUsername) && CommonConstant.STATUS_1.equals(afterNotStatus)) {
//与当前登录用户的username作比对,有相同的并且数据字典为后者不可登录则把redis中的key删除
result.error500("该账户已登录,不可重复登录");
return result;
}
}
}
return result;