作者:jzcpojwmds_652 | 来源:互联网 | 2023-10-10 18:19
为什么要安全验证?对于稍微懂一些电脑的人可以通过抓包方式F12获取秒杀的接口地址,如果有些人根据此自己写了一个脚本进行抢购,如果有人根据获取到的接口写了一个抢购的脚本,那么就可以通
为什么要安全验证?
对于稍微懂一些电脑的人可以通过抓包方式F12获取秒杀的接口地址,如果有些人根据此自己写了一个脚本进行抢购,如果有人根据获取到的接口写了一个抢购的脚本,那么就可以通过不在app界面点击下单按钮就可以下单了,速度比点击下单按钮快得多。所以对于一些用户来说不公平。
安全验证流程?
用户在下单前,先发出一个生成md5hash值的请求,根据自己抢购的商品id和自己的用户Id用Md5加密算法和随机盐生成一个hash值存到redis中,在redis中设置过期时间,等用户真正下单时发起的下单请求(秒杀请求)携带着Md5的hash值和redis中已经存在的hash值作比较是否相等,就能判断此请求是根据脚本发起的请求(没有点击抢购秒杀按钮)还是用户在app下下的单了,避免一些用户的脚本抢购,如果两次md5的值相等,那么就处理下单业务,如果不相等,那么就抛弃请求。
controller.java
md5算法-----service.java
/**** @param id 商品id* @param userId 用户id* @return*/@Overridepublic String getMd5(Integer id, Integer userId) {//验证Userid 存在用户信息User user = userDao.findById(userId);if(user == null){log.info("用户信息: [{}]",user);throw new RuntimeException("用户信息不存在");}//验证id 存在商品信息Stock stock = stockDao.checkStock(id);if(stock == null){//sout打印log.info("商品信息: [{}]",stock.toString());throw new RuntimeException("商品信息不合法");}String hashKey = "KEY_" + userId + "_" +id; //这里!QS#是一个盐 随机生成//生成md5签名放入redis服务String value = DigestUtils.md5DigestAsHex((userId + id + "!Q*jS#").getBytes());stringRedisTemplate.opsForValue().set(hashKey,value,120, TimeUnit.SECONDS);log.info("redis写入: [{}] [{}]",hashKey,value);return value;}
秒杀------service.java
@Overridepublic int killMd5(Integer id, Integer userId, String md5) {//校验redis中秒杀商品是否超时Boolean hasKey = stringRedisTemplate.hasKey("kill"+id);if(!hasKey){throw new RuntimeException("当前商品的抢购时间已截止");}//先验证签名//从redis中获取签名String hashKey = "KEY_" + userId + "_" +id; //这里!QS#是一个盐 随机生成String value = stringRedisTemplate.opsForValue().get(hashKey);//判断redis是否为空if("".equals(value)){throw new RuntimeException("没有携带验证签名,当前请求不合法");}if(!value.equals(md5)){//证明不是同一个用户throw new RuntimeException("当前数据不合法,请稍后再试");}//校验库存Stock stock = checkStock(id);//更新库存updateSale(stock);//创建订单int orderId = createOrder(stock);return orderId;}
不太会,会的时候再继续补充