Commit 5f278ac23b392d6ecd9452cc50fdfc9e77af97e8

Authored by zhougang
1 parent 5bc01901

【新增】优化部分代码风格

yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/annotation/Signature.java renamed to yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/annotation/ApiSignature.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.signature.core.annotation; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.signature.core.annotation;
3 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; 3 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
4 4
5 import java.lang.annotation.*; 5 import java.lang.annotation.*;
  6 +import java.util.concurrent.TimeUnit;
6 7
7 8
8 /** 9 /**
@@ -14,12 +15,17 @@ import java.lang.annotation.*; @@ -14,12 +15,17 @@ import java.lang.annotation.*;
14 @Documented 15 @Documented
15 @Target({ElementType.METHOD, ElementType.TYPE}) 16 @Target({ElementType.METHOD, ElementType.TYPE})
16 @Retention(RetentionPolicy.RUNTIME) 17 @Retention(RetentionPolicy.RUNTIME)
17 -public @interface Signature { 18 +public @interface ApiSignature {
18 19
19 /** 20 /**
20 - * 同一个请求多长时间内有效 默认 10分钟 21 + * 同一个请求多长时间内有效 默认 60 秒
21 */ 22 */
22 - long expireTime() default 600000L; 23 + int timeout() default 60;
  24 +
  25 + /**
  26 + * 时间单位,默认为 SECONDS 秒
  27 + */
  28 + TimeUnit timeUnit() default TimeUnit.SECONDS;
23 29
24 // ========================== 签名参数 ========================== 30 // ========================== 签名参数 ==========================
25 31
@@ -50,8 +56,4 @@ public @interface Signature { @@ -50,8 +56,4 @@ public @interface Signature {
50 */ 56 */
51 String sign() default "sign"; 57 String sign() default "sign";
52 58
53 - /**  
54 - * url 客户端不需要传递,但是可以用来加签(如: /{id} 带有动态参数的 url ,如果没有动态参数可设置为 false 不进行加签)  
55 - */  
56 - boolean urlEnable() default true;  
57 } 59 }
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/SignatureAspect.java
1 package cn.iocoder.yudao.framework.signature.core.aop; 1 package cn.iocoder.yudao.framework.signature.core.aop;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
4 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
5 import cn.hutool.crypto.SignUtil; 6 import cn.hutool.crypto.SignUtil;
6 import cn.iocoder.yudao.framework.common.exception.ServiceException; 7 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; 8 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
8 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 9 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
9 -import cn.iocoder.yudao.framework.signature.core.annotation.Signature; 10 +import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature;
10 import cn.iocoder.yudao.framework.signature.core.redis.SignatureRedisDAO; 11 import cn.iocoder.yudao.framework.signature.core.redis.SignatureRedisDAO;
11 import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyWrapper; 12 import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyWrapper;
12 import jakarta.servlet.http.HttpServletRequest; 13 import jakarta.servlet.http.HttpServletRequest;
@@ -15,7 +16,6 @@ import lombok.extern.slf4j.Slf4j; @@ -15,7 +16,6 @@ import lombok.extern.slf4j.Slf4j;
15 import org.aspectj.lang.JoinPoint; 16 import org.aspectj.lang.JoinPoint;
16 import org.aspectj.lang.annotation.Aspect; 17 import org.aspectj.lang.annotation.Aspect;
17 import org.aspectj.lang.annotation.Before; 18 import org.aspectj.lang.annotation.Before;
18 -import org.springframework.util.Assert;  
19 19
20 import java.nio.charset.StandardCharsets; 20 import java.nio.charset.StandardCharsets;
21 import java.util.Map; 21 import java.util.Map;
@@ -25,7 +25,7 @@ import java.util.TreeMap; @@ -25,7 +25,7 @@ import java.util.TreeMap;
25 import java.util.concurrent.TimeUnit; 25 import java.util.concurrent.TimeUnit;
26 26
27 /** 27 /**
28 - * 拦截声明了 {@link Signature} 注解的方法,实现签名 28 + * 拦截声明了 {@link ApiSignature} 注解的方法,实现签名
29 * 29 *
30 * @author Zhougang 30 * @author Zhougang
31 */ 31 */
@@ -37,9 +37,9 @@ public class SignatureAspect { @@ -37,9 +37,9 @@ public class SignatureAspect {
37 private final SignatureRedisDAO signatureRedisDAO; 37 private final SignatureRedisDAO signatureRedisDAO;
38 38
39 @Before("@annotation(signature)") 39 @Before("@annotation(signature)")
40 - public void beforePointCut(JoinPoint joinPoint, Signature signature) { 40 + public void beforePointCut(JoinPoint joinPoint, ApiSignature signature) {
41 if (!verifySignature(signature, Objects.requireNonNull(ServletUtils.getRequest()))) { 41 if (!verifySignature(signature, Objects.requireNonNull(ServletUtils.getRequest()))) {
42 - log.info("[beforePointCut][方法{} 参数({}) 签名失败]", joinPoint.getSignature().toString(), 42 + log.error("[beforePointCut][方法{} 参数({}) 签名失败]", joinPoint.getSignature().toString(),
43 joinPoint.getArgs()); 43 joinPoint.getArgs());
44 String message = StrUtil.blankToDefault(signature.message(), 44 String message = StrUtil.blankToDefault(signature.message(),
45 GlobalErrorCodeConstants.BAD_REQUEST.getMsg()); 45 GlobalErrorCodeConstants.BAD_REQUEST.getMsg());
@@ -47,25 +47,22 @@ public class SignatureAspect { @@ -47,25 +47,22 @@ public class SignatureAspect {
47 } 47 }
48 } 48 }
49 49
50 - private boolean verifySignature(Signature signature, HttpServletRequest request) { 50 + private boolean verifySignature(ApiSignature signature, HttpServletRequest request) {
51 if (!verifyHeaders(signature, request)) { 51 if (!verifyHeaders(signature, request)) {
52 return false; 52 return false;
53 } 53 }
54 // 校验 appId 是否能获取到对应的 appSecret 54 // 校验 appId 是否能获取到对应的 appSecret
55 String appId = request.getHeader(signature.appId()); 55 String appId = request.getHeader(signature.appId());
56 String appSecret = signatureRedisDAO.getAppSecret(appId); 56 String appSecret = signatureRedisDAO.getAppSecret(appId);
57 - Assert.notNull(appSecret, "找不到对应的 appSecret"); 57 + Assert.notNull(appSecret, "[appId({})] 找不到对应的 appSecret", appId);
58 // 请求头 58 // 请求头
59 SortedMap<String, String> headersMap = getRequestHeaders(signature, request); 59 SortedMap<String, String> headersMap = getRequestHeaders(signature, request);
60 - // 如:/user/{id} url 带有动态参数的情况  
61 - String urlParams = signature.urlEnable() ? request.getServletPath() : "";  
62 // 请求参数 60 // 请求参数
63 String requestParams = getRequestParams(request); 61 String requestParams = getRequestParams(request);
64 // 请求体 62 // 请求体
65 - String requestBody = getRequestBody(request); 63 + String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtils.getBody(request) : "";
66 // 生成服务端签名 64 // 生成服务端签名
67 - String serverSignature = SignUtil.signParamsSha256(headersMap,  
68 - urlParams + requestParams + requestBody + appSecret); 65 + String serverSignature = SignUtil.signParamsSha256(headersMap, requestParams + requestBody + appSecret);
69 // 客户端签名 66 // 客户端签名
70 String clientSignature = request.getHeader(signature.sign()); 67 String clientSignature = request.getHeader(signature.sign());
71 if (!StrUtil.equals(clientSignature, serverSignature)) { 68 if (!StrUtil.equals(clientSignature, serverSignature)) {
@@ -73,7 +70,7 @@ public class SignatureAspect { @@ -73,7 +70,7 @@ public class SignatureAspect {
73 } 70 }
74 String nonce = headersMap.get(signature.nonce()); 71 String nonce = headersMap.get(signature.nonce());
75 // 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 ) 72 // 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 )
76 - signatureRedisDAO.setNonce(nonce, signature.expireTime(), TimeUnit.MILLISECONDS); 73 + signatureRedisDAO.setNonce(nonce, signature.timeout() * 2L, signature.timeUnit());
77 return true; 74 return true;
78 } 75 }
79 76
@@ -87,7 +84,7 @@ public class SignatureAspect { @@ -87,7 +84,7 @@ public class SignatureAspect {
87 * @param signature signature 84 * @param signature signature
88 * @param request request 85 * @param request request
89 */ 86 */
90 - private boolean verifyHeaders(Signature signature, HttpServletRequest request) { 87 + private boolean verifyHeaders(ApiSignature signature, HttpServletRequest request) {
91 String appId = request.getHeader(signature.appId()); 88 String appId = request.getHeader(signature.appId());
92 if (StrUtil.isBlank(appId)) { 89 if (StrUtil.isBlank(appId)) {
93 return false; 90 return false;
@@ -97,7 +94,7 @@ public class SignatureAspect { @@ -97,7 +94,7 @@ public class SignatureAspect {
97 return false; 94 return false;
98 } 95 }
99 String nonce = request.getHeader(signature.nonce()); 96 String nonce = request.getHeader(signature.nonce());
100 - if (StrUtil.isBlank(nonce) || nonce.length() < 10) { 97 + if (StrUtil.isBlank(nonce) || StrUtil.length(nonce) < 10) {
101 return false; 98 return false;
102 } 99 }
103 String sign = request.getHeader(signature.sign()); 100 String sign = request.getHeader(signature.sign());
@@ -105,7 +102,7 @@ public class SignatureAspect { @@ -105,7 +102,7 @@ public class SignatureAspect {
105 return false; 102 return false;
106 } 103 }
107 // 其他合法性校验 104 // 其他合法性校验
108 - long expireTime = signature.expireTime(); 105 + long expireTime = signature.timeUnit().toMillis(signature.timeout());
109 long requestTimestamp = Long.parseLong(timestamp); 106 long requestTimestamp = Long.parseLong(timestamp);
110 // 检查 timestamp 是否超出允许的范围 (重点一:此处需要取绝对值) 107 // 检查 timestamp 是否超出允许的范围 (重点一:此处需要取绝对值)
111 long timestampDisparity = Math.abs(System.currentTimeMillis() - requestTimestamp); 108 long timestampDisparity = Math.abs(System.currentTimeMillis() - requestTimestamp);
@@ -122,7 +119,7 @@ public class SignatureAspect { @@ -122,7 +119,7 @@ public class SignatureAspect {
122 * @param request request 119 * @param request request
123 * @return signature params 120 * @return signature params
124 */ 121 */
125 - private SortedMap<String, String> getRequestHeaders(Signature signature, HttpServletRequest request) { 122 + private SortedMap<String, String> getRequestHeaders(ApiSignature signature, HttpServletRequest request) {
126 SortedMap<String, String> sortedMap = new TreeMap<>(); 123 SortedMap<String, String> sortedMap = new TreeMap<>();
127 sortedMap.put(signature.appId(), request.getHeader(signature.appId())); 124 sortedMap.put(signature.appId(), request.getHeader(signature.appId()));
128 sortedMap.put(signature.timestamp(), request.getHeader(signature.timestamp())); 125 sortedMap.put(signature.timestamp(), request.getHeader(signature.timestamp()));
@@ -154,17 +151,5 @@ public class SignatureAspect { @@ -154,17 +151,5 @@ public class SignatureAspect {
154 return queryString.substring(1); 151 return queryString.substring(1);
155 } 152 }
156 153
157 - /**  
158 - * 获取请求体参数  
159 - *  
160 - * @param request request  
161 - * @return body  
162 - */  
163 - private String getRequestBody(HttpServletRequest request) {  
164 - CacheRequestBodyWrapper requestWrapper = new CacheRequestBodyWrapper(request);  
165 - // 获取 body  
166 - return new String(requestWrapper.getBody(), StandardCharsets.UTF_8);  
167 - }  
168 -  
169 } 154 }
170 155
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/SignatureRedisDAO.java
@@ -42,8 +42,7 @@ public class SignatureRedisDAO { @@ -42,8 +42,7 @@ public class SignatureRedisDAO {
42 } 42 }
43 43
44 public void setNonce(String nonce, long time, TimeUnit timeUnit) { 44 public void setNonce(String nonce, long time, TimeUnit timeUnit) {
45 - // 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 )  
46 - stringRedisTemplate.opsForValue().set(formatNonceKey(nonce), nonce, time * 2, timeUnit); 45 + stringRedisTemplate.opsForValue().set(formatNonceKey(nonce), nonce, time, timeUnit);
47 } 46 }
48 47
49 private static String formatAppIdKey(String key) { 48 private static String formatAppIdKey(String key) {
yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
1 cn.iocoder.yudao.framework.idempotent.config.YudaoIdempotentConfiguration 1 cn.iocoder.yudao.framework.idempotent.config.YudaoIdempotentConfiguration
2 cn.iocoder.yudao.framework.lock4j.config.YudaoLock4jConfiguration 2 cn.iocoder.yudao.framework.lock4j.config.YudaoLock4jConfiguration
3 -cn.iocoder.yudao.framework.ratelimiter.config.YudaoRateLimiterConfiguration  
4 \ No newline at end of file 3 \ No newline at end of file
  4 +cn.iocoder.yudao.framework.ratelimiter.config.YudaoRateLimiterConfiguration
  5 +cn.iocoder.yudao.framework.signature.config.YudaoSignatureAutoConfiguration
5 \ No newline at end of file 6 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyWrapper.java
@@ -23,10 +23,6 @@ public class CacheRequestBodyWrapper extends HttpServletRequestWrapper { @@ -23,10 +23,6 @@ public class CacheRequestBodyWrapper extends HttpServletRequestWrapper {
23 */ 23 */
24 private final byte[] body; 24 private final byte[] body;
25 25
26 - public byte[] getBody() {  
27 - return body;  
28 - }  
29 -  
30 public CacheRequestBodyWrapper(HttpServletRequest request) { 26 public CacheRequestBodyWrapper(HttpServletRequest request) {
31 super(request); 27 super(request);
32 body = ServletUtils.getBodyBytes(request); 28 body = ServletUtils.getBodyBytes(request);