Browse Source

对外开放API校验注解

hanzhengyi 1 year ago
parent
commit
655d51e9b0

+ 4 - 0
pom.xml

@@ -71,6 +71,10 @@
     
     <module>service-park</module>
 
+
+
+    <module>service-issue</module>
+
   </modules>
           
   

+ 10 - 1
service-issue/service-issue-biz/src/main/java/com/usky/issue/annotation/CheckSign.java

@@ -1,2 +1,11 @@
-package com.usky.issue.annotation;public @interface CheckSign {
+package com.usky.issue.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME )
+public @interface CheckSign {
 }

+ 91 - 1
service-issue/service-issue-biz/src/main/java/com/usky/issue/annotation/CheckSignAspect.java

@@ -1,2 +1,92 @@
-package com.usky.issue.annotation;public class CheckSignAspect {
+package com.usky.issue.annotation;
+
+import com.usky.common.core.utils.StringUtils;
+import com.usky.issue.service.util.SignUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.util.ContentCachingRequestWrapper;
+
+import javax.servlet.http.HttpServletRequest;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.Objects;
+
+@Aspect   //定义一个切面
+@Configuration
+@Slf4j
+public class CheckSignAspect {
+
+    @Value("${sign.expireTime}")
+    private long expireTime;//接口签名验证超时时间
+    @Value("${sign.secretKey}")
+    private String secretKey;//接口签名唯一密钥
+
+    // 定义切点Pointcut
+    @Pointcut("@annotation(com.usky.issue.annotation.CheckSign)")
+    public void excudeService() {
+    }
+
+    @Around("excudeService()")
+    public Object doAround(ProceedingJoinPoint joinPoint) {
+        log.info("开始验证签名");
+        try {
+            ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+            HttpServletRequest request = Objects.requireNonNull(sra).getRequest();
+
+            String timestamp = request.getHeader("timestamp");//获取timestamp参数
+            String sign = request.getHeader("sign");//获取sign参数
+
+            if (StringUtils.isBlank(timestamp) || StringUtils.isBlank(sign)) {
+                return "timestamp和sign参数不能为空";
+            }
+            long requestTime = Long.valueOf(timestamp);
+            long now = System.currentTimeMillis() / 1000;
+            log.info("now={}", now);
+            // 请求发起时间与当前时间超过expireTime,则接口请求过期
+            if (now - requestTime > expireTime) {
+                return "接口请求过期";
+            }
+
+            String generatedSign = generatedSignature(request, timestamp);
+            if (!generatedSign.equals(sign)) {
+                return "签名校验错误";
+            }
+
+            Object result = joinPoint.proceed();
+            return result;
+        } catch (Throwable t) {
+            return "签名校验异常";
+        }
+
+    }
+
+    //获取请求参数并生成签名
+    private String generatedSignature(HttpServletRequest request, String timestamp) {
+        //获取RequestBody参数,此处需要配合过滤器处理request后才能获取
+        String bodyParam = null;
+        if (request instanceof ContentCachingRequestWrapper) {
+            bodyParam = new String(((ContentCachingRequestWrapper) request).getContentAsByteArray(), StandardCharsets.UTF_8);
+        }
+
+        //获取RequestParam参数
+        Map<String, String[]> requestParameterMap = request.getParameterMap();
+
+        //获取PathVariable参数
+        ServletWebRequest webRequest = new ServletWebRequest(request, null);
+        Map<String, String> requestPathMap = (Map<String, String>) webRequest.getAttribute(
+                HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
+
+        return SignUtil.sign(bodyParam, requestParameterMap, requestPathMap, secretKey, timestamp);
+    }
+
 }

+ 54 - 1
service-issue/service-issue-biz/src/main/java/com/usky/issue/service/util/SignUtil.java

@@ -1,2 +1,55 @@
-package com.usky.issue.service.util;public class SignUtil {
+package com.usky.issue.service.util;
+
+import cn.hutool.crypto.SecureUtil;
+import com.usky.common.core.utils.StringUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class SignUtil {
+
+    /**
+     * 使用 Map按key进行排序
+     *
+     * @param map
+     * @return
+     */
+    public static Map<String, String> sortMapByKey(Map<String, String> map) {
+        if (map == null || map.isEmpty()) {
+            return null;
+        }
+        //升序排序
+        Map<String, String> sortMap = new TreeMap<>(String::compareTo);
+        sortMap.putAll(map);
+        return sortMap;
+    }
+
+    public static String sign(String body, Map<String, String[]> params, Map<String, String> requestPathMap, String secretKey, String timestamp) {
+        StringBuilder sb = new StringBuilder();
+        if (StringUtils.isNotBlank(body)) {
+            sb.append(body).append('#');
+        }
+
+        if (!CollectionUtils.isEmpty(params)) {
+            params.entrySet()
+                    .stream()
+                    .sorted(Map.Entry.comparingByKey())
+                    .forEach(paramEntry -> {
+                        String paramValue = String.join(",", Arrays.stream(paramEntry.getValue()).sorted().toArray(String[]::new));
+                        sb.append(paramEntry.getKey()).append("=").append(paramValue).append('#');
+                    });
+        }
+
+        if (!CollectionUtils.isEmpty(requestPathMap)) {
+            for (String key : requestPathMap.keySet()) {
+                String value = requestPathMap.get(key);
+                sb.append(key).append("=").append(value).append('#');
+            }
+
+        }
+        String a = String.join("#", secretKey, timestamp, sb.toString());
+        return SecureUtil.md5(a);
+    }
 }