171 fix(protection): 修复HTTP接口签名 API重复请求问题
This commit is contained in:
parent
4d88cfdf86
commit
f6601ab639
|
@ -2,10 +2,12 @@ package cn.iocoder.yudao.framework.signature.core.aop;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.BooleanUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.crypto.digest.DigestUtil;
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature;
|
import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature;
|
||||||
import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO;
|
import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO;
|
||||||
|
@ -69,13 +71,17 @@ public class ApiSignatureAspect {
|
||||||
|
|
||||||
// 3. 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 )
|
// 3. 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 )
|
||||||
String nonce = request.getHeader(signature.nonce());
|
String nonce = request.getHeader(signature.nonce());
|
||||||
signatureRedisDAO.setNonce(appId, nonce, signature.timeout() * 2, signature.timeUnit());
|
if (BooleanUtil.isFalse(signatureRedisDAO.setNonce(appId, nonce, signature.timeout() * 2, signature.timeUnit()))) {
|
||||||
|
String timestamp = request.getHeader(signature.timestamp());
|
||||||
|
log.info("[verifySignature][appId({}) timestamp({}) nonce({}) sign({}) 存在重复请求]", appId, timestamp, nonce, clientSignature);
|
||||||
|
throw new ServiceException(GlobalErrorCodeConstants.REPEATED_REQUESTS.getCode(), "存在重复请求");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验请求头加签参数
|
* 校验请求头加签参数
|
||||||
*
|
* <p>
|
||||||
* 1. appId 是否为空
|
* 1. appId 是否为空
|
||||||
* 2. timestamp 是否为空,请求是否已经超时,默认 10 分钟
|
* 2. timestamp 是否为空,请求是否已经超时,默认 10 分钟
|
||||||
* 3. nonce 是否为空,随机数是否 10 位以上,是否在规定时间内已经访问过了
|
* 3. nonce 是否为空,随机数是否 10 位以上,是否在规定时间内已经访问过了
|
||||||
|
@ -118,7 +124,7 @@ public class ApiSignatureAspect {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建签名字符串
|
* 构建签名字符串
|
||||||
*
|
* <p>
|
||||||
* 格式为 = 请求参数 + 请求体 + 请求头 + 密钥
|
* 格式为 = 请求参数 + 请求体 + 请求头 + 密钥
|
||||||
*
|
*
|
||||||
* @param signature signature
|
* @param signature signature
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class ApiSignatureRedisDAO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验签随机数
|
* 验签随机数
|
||||||
*
|
* <p>
|
||||||
* KEY 格式:signature_nonce:%s // 参数为 随机数
|
* KEY 格式:signature_nonce:%s // 参数为 随机数
|
||||||
* VALUE 格式:String
|
* VALUE 格式:String
|
||||||
* 过期时间:不固定
|
* 过期时间:不固定
|
||||||
|
@ -26,7 +26,7 @@ public class ApiSignatureRedisDAO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 签名密钥
|
* 签名密钥
|
||||||
*
|
* <p>
|
||||||
* HASH 结构
|
* HASH 结构
|
||||||
* KEY 格式:%s // 参数为 appid
|
* KEY 格式:%s // 参数为 appid
|
||||||
* VALUE 格式:String
|
* VALUE 格式:String
|
||||||
|
@ -40,8 +40,8 @@ public class ApiSignatureRedisDAO {
|
||||||
return stringRedisTemplate.opsForValue().get(formatNonceKey(appId, nonce));
|
return stringRedisTemplate.opsForValue().get(formatNonceKey(appId, nonce));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNonce(String appId, String nonce, int time, TimeUnit timeUnit) {
|
public Boolean setNonce(String appId, String nonce, int time, TimeUnit timeUnit) {
|
||||||
stringRedisTemplate.opsForValue().set(formatNonceKey(appId, nonce), "", time, timeUnit);
|
return stringRedisTemplate.opsForValue().setIfAbsent(formatNonceKey(appId, nonce), "", time, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String formatNonceKey(String appId, String nonce) {
|
private static String formatNonceKey(String appId, String nonce) {
|
||||||
|
|
Loading…
Reference in New Issue