Merge remote-tracking branch 'base-version/main' into dev

This commit is contained in:
chenbowen
2025-10-17 17:45:33 +08:00
106 changed files with 4200 additions and 1377 deletions

View File

@@ -1,11 +1,20 @@
package com.zt.plat.framework.signature.config;
import com.zt.plat.framework.redis.config.ZtRedisAutoConfiguration;
import com.zt.plat.framework.signature.core.aop.ApiSignatureAspect;
import com.zt.plat.framework.signature.core.ApiSignatureVerifier;
import com.zt.plat.framework.signature.core.config.ApiSignatureProperties;
import com.zt.plat.framework.signature.core.redis.ApiSignatureRedisDAO;
import com.zt.plat.framework.signature.core.web.ApiSignatureHandlerInterceptor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* HTTP API 签名的自动配置类
@@ -13,16 +22,47 @@ import org.springframework.data.redis.core.StringRedisTemplate;
* @author Zhougang
*/
@AutoConfiguration(after = ZtRedisAutoConfiguration.class)
@EnableConfigurationProperties(ApiSignatureProperties.class)
public class ZtApiSignatureAutoConfiguration {
@Bean
public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO) {
return new ApiSignatureAspect(signatureRedisDAO);
}
@Bean
public ApiSignatureRedisDAO signatureRedisDAO(StringRedisTemplate stringRedisTemplate) {
return new ApiSignatureRedisDAO(stringRedisTemplate);
}
@Bean
public ApiSignatureVerifier apiSignatureVerifier(ApiSignatureRedisDAO signatureRedisDAO) {
return new ApiSignatureVerifier(signatureRedisDAO);
}
@Bean
public ApiSignatureHandlerInterceptor apiSignatureHandlerInterceptor(ApiSignatureVerifier verifier,
ApiSignatureProperties properties) {
return new ApiSignatureHandlerInterceptor(verifier, properties);
}
@Bean
public WebMvcConfigurer apiSignatureWebMvcConfigurer(ApiSignatureHandlerInterceptor interceptor,
ApiSignatureProperties properties) {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
if (!properties.isEnabled()) {
return;
}
InterceptorRegistration registration = registry.addInterceptor(interceptor);
List<String> includePaths = properties.getIncludePaths();
if (CollectionUtils.isEmpty(includePaths)) {
registration.addPathPatterns("/**");
} else {
registration.addPathPatterns(includePaths.toArray(new String[0]));
}
List<String> excludePaths = properties.getExcludePaths();
if (!CollectionUtils.isEmpty(excludePaths)) {
registration.excludePathPatterns(excludePaths.toArray(new String[0]));
}
}
};
}
}

View File

@@ -0,0 +1,68 @@
package com.zt.plat.framework.signature.core.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* API 签名配置
*/
@Data
@ConfigurationProperties(prefix = "zt.api-signature")
public class ApiSignatureProperties {
/**
* 是否开启全局签名校验
*/
private boolean enabled = true;
/**
* 签名有效期
*/
private int timeout = 60;
/**
* 时间单位
*/
private TimeUnit timeUnit = TimeUnit.SECONDS;
/**
* 校验失败时的提示信息
*/
private String message = "签名不正确";
/**
* 请求头appId
*/
private String appId = "appId";
/**
* 请求头timestamp
*/
private String timestamp = "timestamp";
/**
* 请求头nonce
*/
private String nonce = "nonce";
/**
* 请求头sign
*/
private String sign = "sign";
/**
* 需要进行签名校验的路径,默认全量
*/
private List<String> includePaths = new ArrayList<>(Arrays.asList("/**"));
/**
* 无需签名校验的路径
*/
private List<String> excludePaths = new ArrayList<>(Arrays.asList("/error", "/swagger-ui/**", "/v3/api-docs/**"));
}

View File

@@ -0,0 +1,50 @@
package com.zt.plat.framework.signature.core.model;
import cn.hutool.core.util.StrUtil;
import com.zt.plat.framework.signature.core.annotation.ApiSignature;
import com.zt.plat.framework.signature.core.config.ApiSignatureProperties;
import lombok.Builder;
import lombok.Getter;
import java.util.concurrent.TimeUnit;
/**
* 签名校验规则
*/
@Getter
@Builder
public class ApiSignatureRule {
private final int timeout;
private final TimeUnit timeUnit;
private final String message;
private final String appId;
private final String timestamp;
private final String nonce;
private final String sign;
public static ApiSignatureRule from(ApiSignatureProperties properties) {
return ApiSignatureRule.builder()
.timeout(properties.getTimeout())
.timeUnit(properties.getTimeUnit())
.message(properties.getMessage())
.appId(properties.getAppId())
.timestamp(properties.getTimestamp())
.nonce(properties.getNonce())
.sign(properties.getSign())
.build();
}
public static ApiSignatureRule from(ApiSignature signature, ApiSignatureProperties defaults) {
return ApiSignatureRule.builder()
.timeout(signature.timeout())
.timeUnit(signature.timeUnit())
.message(StrUtil.blankToDefault(signature.message(), defaults.getMessage()))
.appId(signature.appId())
.timestamp(signature.timestamp())
.nonce(signature.nonce())
.sign(signature.sign())
.build();
}
}

View File

@@ -0,0 +1,80 @@
package com.zt.plat.framework.signature.core.web;
import com.zt.plat.framework.signature.core.ApiSignatureVerifier;
import com.zt.plat.framework.signature.core.annotation.ApiSignature;
import com.zt.plat.framework.signature.core.config.ApiSignatureProperties;
import com.zt.plat.framework.signature.core.model.ApiSignatureRule;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.UrlPathHelper;
import java.util.List;
/**
* 全局 API 签名拦截器
*/
@RequiredArgsConstructor
public class ApiSignatureHandlerInterceptor implements HandlerInterceptor {
private final ApiSignatureVerifier verifier;
private final ApiSignatureProperties properties;
private final AntPathMatcher pathMatcher = new AntPathMatcher();
private final UrlPathHelper urlPathHelper = new UrlPathHelper();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!properties.isEnabled()) {
return true;
}
if (!(handler instanceof HandlerMethod handlerMethod)) {
return true;
}
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
return true;
}
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
if (shouldSkip(lookupPath)) {
return true;
}
ApiSignatureRule rule = createRule(handlerMethod);
verifier.verify(rule, request);
return true;
}
private boolean shouldSkip(String path) {
List<String> includePaths = properties.getIncludePaths();
if (!CollectionUtils.isEmpty(includePaths)) {
boolean matched = includePaths.stream().anyMatch(pattern -> pathMatcher.match(pattern, path));
if (!matched) {
return true;
}
}
List<String> excludePaths = properties.getExcludePaths();
if (!CollectionUtils.isEmpty(excludePaths)) {
for (String pattern : excludePaths) {
if (pathMatcher.match(pattern, path)) {
return true;
}
}
}
return false;
}
private ApiSignatureRule createRule(HandlerMethod handlerMethod) {
ApiSignature signature = handlerMethod.getMethodAnnotation(ApiSignature.class);
if (signature != null) {
return ApiSignatureRule.from(signature, properties);
}
signature = handlerMethod.getBeanType().getAnnotation(ApiSignature.class);
if (signature != null) {
return ApiSignatureRule.from(signature, properties);
}
return ApiSignatureRule.from(properties);
}
}

View File

@@ -1,4 +1,3 @@
com.zt.plat.framework.idempotent.config.ZtIdempotentConfiguration
com.zt.plat.framework.lock4j.config.ZtLock4jConfiguration
com.zt.plat.framework.ratelimiter.config.ZtRateLimiterConfiguration
com.zt.plat.framework.signature.config.ZtApiSignatureAutoConfiguration