From f6601ab6390a9a36facec8df78cecb2ccfdf557d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 12 Apr 2025 11:32:18 +0800 Subject: [PATCH] =?UTF-8?q?171=20fix(protection):=20=E4=BF=AE=E5=A4=8DHTTP?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=AD=BE=E5=90=8D=20API=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signature/core/aop/ApiSignatureAspect.java | 14 ++++++++++---- .../signature/core/redis/ApiSignatureRedisDAO.java | 8 ++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java index c1c78ac57b..e568346aa3 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java @@ -2,10 +2,12 @@ package cn.iocoder.yudao.framework.signature.core.aop; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.DigestUtil; 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.signature.core.annotation.ApiSignature; import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO; @@ -69,13 +71,17 @@ public class ApiSignatureAspect { // 3. 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 ) 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; } /** * 校验请求头加签参数 - * + *

* 1. appId 是否为空 * 2. timestamp 是否为空,请求是否已经超时,默认 10 分钟 * 3. nonce 是否为空,随机数是否 10 位以上,是否在规定时间内已经访问过了 @@ -118,7 +124,7 @@ public class ApiSignatureAspect { /** * 构建签名字符串 - * + *

* 格式为 = 请求参数 + 请求体 + 请求头 + 密钥 * * @param signature signature @@ -139,7 +145,7 @@ public class ApiSignatureAspect { /** * 获取请求头加签参数 Map * - * @param request 请求 + * @param request 请求 * @param signature 签名注解 * @return signature params */ diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java index 11fe384dac..7f3b119d53 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java @@ -17,7 +17,7 @@ public class ApiSignatureRedisDAO { /** * 验签随机数 - * + *

* KEY 格式:signature_nonce:%s // 参数为 随机数 * VALUE 格式:String * 过期时间:不固定 @@ -26,7 +26,7 @@ public class ApiSignatureRedisDAO { /** * 签名密钥 - * + *

* HASH 结构 * KEY 格式:%s // 参数为 appid * VALUE 格式:String @@ -40,8 +40,8 @@ public class ApiSignatureRedisDAO { return stringRedisTemplate.opsForValue().get(formatNonceKey(appId, nonce)); } - public void setNonce(String appId, String nonce, int time, TimeUnit timeUnit) { - stringRedisTemplate.opsForValue().set(formatNonceKey(appId, nonce), "", time, timeUnit); + public Boolean setNonce(String appId, String nonce, int time, TimeUnit timeUnit) { + return stringRedisTemplate.opsForValue().setIfAbsent(formatNonceKey(appId, nonce), "", time, timeUnit); } private static String formatNonceKey(String appId, String nonce) {