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 3 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
4 4  
5 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 15 @Documented
15 16 @Target({ElementType.METHOD, ElementType.TYPE})
16 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 56 */
51 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 1 package cn.iocoder.yudao.framework.signature.core.aop;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
4 5 import cn.hutool.core.util.StrUtil;
5 6 import cn.hutool.crypto.SignUtil;
6 7 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 8 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
8 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 11 import cn.iocoder.yudao.framework.signature.core.redis.SignatureRedisDAO;
11 12 import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyWrapper;
12 13 import jakarta.servlet.http.HttpServletRequest;
... ... @@ -15,7 +16,6 @@ import lombok.extern.slf4j.Slf4j;
15 16 import org.aspectj.lang.JoinPoint;
16 17 import org.aspectj.lang.annotation.Aspect;
17 18 import org.aspectj.lang.annotation.Before;
18   -import org.springframework.util.Assert;
19 19  
20 20 import java.nio.charset.StandardCharsets;
21 21 import java.util.Map;
... ... @@ -25,7 +25,7 @@ import java.util.TreeMap;
25 25 import java.util.concurrent.TimeUnit;
26 26  
27 27 /**
28   - * 拦截声明了 {@link Signature} 注解的方法,实现签名
  28 + * 拦截声明了 {@link ApiSignature} 注解的方法,实现签名
29 29 *
30 30 * @author Zhougang
31 31 */
... ... @@ -37,9 +37,9 @@ public class SignatureAspect {
37 37 private final SignatureRedisDAO signatureRedisDAO;
38 38  
39 39 @Before("@annotation(signature)")
40   - public void beforePointCut(JoinPoint joinPoint, Signature signature) {
  40 + public void beforePointCut(JoinPoint joinPoint, ApiSignature signature) {
41 41 if (!verifySignature(signature, Objects.requireNonNull(ServletUtils.getRequest()))) {
42   - log.info("[beforePointCut][方法{} 参数({}) 签名失败]", joinPoint.getSignature().toString(),
  42 + log.error("[beforePointCut][方法{} 参数({}) 签名失败]", joinPoint.getSignature().toString(),
43 43 joinPoint.getArgs());
44 44 String message = StrUtil.blankToDefault(signature.message(),
45 45 GlobalErrorCodeConstants.BAD_REQUEST.getMsg());
... ... @@ -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 51 if (!verifyHeaders(signature, request)) {
52 52 return false;
53 53 }
54 54 // 校验 appId 是否能获取到对应的 appSecret
55 55 String appId = request.getHeader(signature.appId());
56 56 String appSecret = signatureRedisDAO.getAppSecret(appId);
57   - Assert.notNull(appSecret, "找不到对应的 appSecret");
  57 + Assert.notNull(appSecret, "[appId({})] 找不到对应的 appSecret", appId);
58 58 // 请求头
59 59 SortedMap<String, String> headersMap = getRequestHeaders(signature, request);
60   - // 如:/user/{id} url 带有动态参数的情况
61   - String urlParams = signature.urlEnable() ? request.getServletPath() : "";
62 60 // 请求参数
63 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 67 String clientSignature = request.getHeader(signature.sign());
71 68 if (!StrUtil.equals(clientSignature, serverSignature)) {
... ... @@ -73,7 +70,7 @@ public class SignatureAspect {
73 70 }
74 71 String nonce = headersMap.get(signature.nonce());
75 72 // 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 )
76   - signatureRedisDAO.setNonce(nonce, signature.expireTime(), TimeUnit.MILLISECONDS);
  73 + signatureRedisDAO.setNonce(nonce, signature.timeout() * 2L, signature.timeUnit());
77 74 return true;
78 75 }
79 76  
... ... @@ -87,7 +84,7 @@ public class SignatureAspect {
87 84 * @param signature signature
88 85 * @param request request
89 86 */
90   - private boolean verifyHeaders(Signature signature, HttpServletRequest request) {
  87 + private boolean verifyHeaders(ApiSignature signature, HttpServletRequest request) {
91 88 String appId = request.getHeader(signature.appId());
92 89 if (StrUtil.isBlank(appId)) {
93 90 return false;
... ... @@ -97,7 +94,7 @@ public class SignatureAspect {
97 94 return false;
98 95 }
99 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 98 return false;
102 99 }
103 100 String sign = request.getHeader(signature.sign());
... ... @@ -105,7 +102,7 @@ public class SignatureAspect {
105 102 return false;
106 103 }
107 104 // 其他合法性校验
108   - long expireTime = signature.expireTime();
  105 + long expireTime = signature.timeUnit().toMillis(signature.timeout());
109 106 long requestTimestamp = Long.parseLong(timestamp);
110 107 // 检查 timestamp 是否超出允许的范围 (重点一:此处需要取绝对值)
111 108 long timestampDisparity = Math.abs(System.currentTimeMillis() - requestTimestamp);
... ... @@ -122,7 +119,7 @@ public class SignatureAspect {
122 119 * @param request request
123 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 123 SortedMap<String, String> sortedMap = new TreeMap<>();
127 124 sortedMap.put(signature.appId(), request.getHeader(signature.appId()));
128 125 sortedMap.put(signature.timestamp(), request.getHeader(signature.timestamp()));
... ... @@ -154,17 +151,5 @@ public class SignatureAspect {
154 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 42 }
43 43  
44 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 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 1 cn.iocoder.yudao.framework.idempotent.config.YudaoIdempotentConfiguration
2 2 cn.iocoder.yudao.framework.lock4j.config.YudaoLock4jConfiguration
3   -cn.iocoder.yudao.framework.ratelimiter.config.YudaoRateLimiterConfiguration
4 3 \ No newline at end of file
  4 +cn.iocoder.yudao.framework.ratelimiter.config.YudaoRateLimiterConfiguration
  5 +cn.iocoder.yudao.framework.signature.config.YudaoSignatureAutoConfiguration
5 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 23 */
24 24 private final byte[] body;
25 25  
26   - public byte[] getBody() {
27   - return body;
28   - }
29   -
30 26 public CacheRequestBodyWrapper(HttpServletRequest request) {
31 27 super(request);
32 28 body = ServletUtils.getBodyBytes(request);
... ...