我们后台管理系统冻结用户发送请求携带userid
普通版本:
1.通过userid我们可以作为Redis的key的一部分(最好携带前缀拼接便于看到key就明白内容)
2.我们把用户冻结的信息(冻结原因、时间、备注、冻结的范围:例如冻结发言、冻结登录之类的)可以创建实体类、或者使用map集合吧数据存起来("使用map集合可以不用创建新的实体类,适用于字段比较少的时候、字段不确定时候")。
然后使用json工具类(例如fastjson)把map转成字符串然后使用springboot整合Redis的StringRedisTemplate,其中StringRedisTemplate和RedisTemplate的最大区别就是,存在StringRedisTemplate中的value是以string类型存储着,而RedisTemplate是会把对象序列化存储,如果使用StringRedisTemplate就取出value后可以再使用json转成map集合就方便许多。StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
这里我是使用StringRedisTemplate
3.设置token有效期
使用switch比if更直观,因为多条件判断,我们使用if会一直if..else..使我们的代码变得很杂乱,使用switch直观。而且到时候我们添加多新的冻结日期只需要多加一行即可
高级版本
高级点的版本是我想到了,如果登录用户被冻结了登录,而我们需要的是userid来作为redis中的key一部分。所以我们每次登录时候,例如用户传进来手机号码、或者用户名来进行登录。我们还得帮他们查找数据库得到id才能进行Redis的校验是否被冻结?
这就导致了一些人可以使用for循环一直登录,即使被冻结了。还是会不断的刷我们数据库浪费性能。
所以我们可以使用用户名或者手机号来作为key的一部分可以防止这样的攻击。
代码:
//1.获取用户id,得到手机号拼接前缀为key
Integer userId = (Integer) map.get("userId");
String phone=userApi.findUserPhoneByUserId(userId);
String key="FreezeUser_"+phone;
//2.获取用户冻结信息、冻结类型、冻结时间、冻结id(手机号)
Integer freezingTime = Integer.valueOf(map.get("freezingTime").toString());
String freezeInfo = JSON.toJSONString(map);
//3.冻结用户,存到Redis中
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
switch (freezingTime){
//冻结3天
case 1: ops.set(key,freezeInfo,3, TimeUnit.DAYS);break;
//冻结7天
case 2: ops.set(key,freezeInfo,7, TimeUnit.DAYS);break;
//永久冻结
case 3: ops.set(key,freezeInfo);break;
default:break;
}
Map<String,String> resultMap=new HashMap<>();
resultMap.put("message",map.get("reasonsForFreezing").toString());
//随便修改userinfo的数据库字段userStatus为2
UserInfo userinfo = userInfoApi.findUserInfoById(userId.longValue());
userinfo.setUserStatus("2");
userInfoApi.save(userinfo);
我们举登陆页面为例子
在我们登陆页面直接根据手机号判断是否符合要求即可
我们使用fastjosn转为map(这里使用parseObject(String text)得到JSONObject)
因为JSONObject本质也是个map
public class JSONObject extends JSON implements Map<String, Object>, Cloneable, Serializable, InvocationHandler
String phone = map.get("phone");
//0.冻结判断
String json = stringRedisTemplate.opsForValue().get("FreezeUser_" + phone);
//判断是value否为null
if(StringUtils.isNotEmpty(json)){
JSONObject jsonObject = JSON.parseObject(json);
String freezingRange = jsonObject.get("freezingRange").toString();
//判断冻结状态
if(StringUtils.equals(freezingRange,"1")){
//这里如果freezingRange等于1,代表他是登录被冻结了直接抛异常 加上异常原因
throw new MyException("登录被冻结!"+jsonObject.getString("reasonsForFreezing")));
}
}
以上为代码实现,哪里功能需要被冻结可以加上去,可以抽取工具类做方法传入登陆用户的手机号、状态类型即可(这里我使用的是状态类型string内容是数字)
扩展:
我们还可以使用网关来限制同一个ip的发送多次注册,例如注册腾讯云同一个ip只能限制一次
我们可以创建冻结表、解冻表、这样方便我们日后维护。比如查看哪些用户是惯犯?哪些用户被误封了,需要解封(使用解冻表,删除Redis中的key记录到解冻表中)?
当然一些人会问为什么要使用数据库来存储冻结表?使用日志不好?
原因有几点:
1.我们这是后台管理系统,平时用的比较少,所以我们不用担心mysql数据库性能不够、存储量也不会太大。
2.我们使用冻结表可以在记录到Redis时候记录下来,这样可以防止Redis宕机数据丢失。
3.我们使用日志还需要解析日志才能得到数据。