1、结构调整
2、抽象工厂优化
This commit is contained in:
@@ -2,18 +2,21 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>msgpush-framework</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>msgpush-spring-boot-starter-web</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>Web 框架,全局异常、API 日志、脱敏、错误码等</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -86,4 +89,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
@@ -2,10 +2,10 @@ package com.njcn.msgpush.framework.apilog.config;
|
||||
|
||||
import com.njcn.msgpush.framework.apilog.core.filter.ApiAccessLogFilter;
|
||||
import com.njcn.msgpush.framework.apilog.core.interceptor.ApiAccessLogInterceptor;
|
||||
import com.njcn.msgpush.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.ApiAccessLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.enums.WebFilterOrderEnum;
|
||||
import com.njcn.msgpush.framework.web.config.WebProperties;
|
||||
import com.njcn.msgpush.framework.web.config.MsgpushWebAutoConfiguration;
|
||||
import com.njcn.msgpush.framework.web.config.WebProperties;
|
||||
import jakarta.servlet.Filter;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.njcn.msgpush.framework.apilog.config;
|
||||
|
||||
import com.njcn.msgpush.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.ApiAccessLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.ApiErrorLogCommonApi;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.Getter;
|
||||
/**
|
||||
* 操作日志的操作类型
|
||||
*
|
||||
* @author ruoyi
|
||||
* @author hongawen
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
|
||||
@@ -7,10 +7,11 @@ import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.njcn.msgpush.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import com.njcn.msgpush.framework.apilog.core.enums.OperateTypeEnum;
|
||||
import com.njcn.msgpush.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.ApiAccessLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
|
||||
import com.njcn.msgpush.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.json.JsonUtils;
|
||||
@@ -19,7 +20,6 @@ import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
import com.njcn.msgpush.framework.web.config.WebProperties;
|
||||
import com.njcn.msgpush.framework.web.core.filter.ApiRequestFilter;
|
||||
import com.njcn.msgpush.framework.web.core.util.WebFrameworkUtils;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.FilterChain;
|
||||
|
||||
@@ -1,38 +1,21 @@
|
||||
package com.njcn.msgpush.framework.apilog.core.interceptor;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
import com.njcn.msgpush.framework.common.util.spring.SpringUtils;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* API 访问日志 Interceptor
|
||||
*
|
||||
* 目的:在非 prod 环境时,打印 request 和 response 两条日志到日志文件(控制台)中。
|
||||
* 目的:记录 HandlerMethod,提供给 ApiAccessLogFilter 使用
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
@Slf4j
|
||||
public class ApiAccessLogInterceptor implements HandlerInterceptor {
|
||||
|
||||
public static final String ATTRIBUTE_HANDLER_METHOD = "HANDLER_METHOD";
|
||||
|
||||
private static final String ATTRIBUTE_STOP_WATCH = "ApiAccessLogInterceptor.StopWatch";
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
// 记录 HandlerMethod,提供给 ApiAccessLogFilter 使用
|
||||
@@ -40,64 +23,11 @@ public class ApiAccessLogInterceptor implements HandlerInterceptor {
|
||||
if (handlerMethod != null) {
|
||||
request.setAttribute(ATTRIBUTE_HANDLER_METHOD, handlerMethod);
|
||||
}
|
||||
|
||||
// 打印 request 日志
|
||||
if (!SpringUtils.isProd()) {
|
||||
Map<String, String> queryString = ServletUtils.getParamMap(request);
|
||||
String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtils.getBody(request) : null;
|
||||
if (CollUtil.isEmpty(queryString) && StrUtil.isEmpty(requestBody)) {
|
||||
log.info("[preHandle][开始请求 URL({}) 无参数]", request.getRequestURI());
|
||||
} else {
|
||||
log.info("[preHandle][开始请求 URL({}) 参数({})]", request.getRequestURI(),
|
||||
StrUtil.blankToDefault(requestBody, queryString.toString()));
|
||||
}
|
||||
// 计时
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
request.setAttribute(ATTRIBUTE_STOP_WATCH, stopWatch);
|
||||
// 打印 Controller 路径
|
||||
printHandlerMethodPosition(handlerMethod);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||
// 打印 response 日志
|
||||
if (!SpringUtils.isProd()) {
|
||||
StopWatch stopWatch = (StopWatch) request.getAttribute(ATTRIBUTE_STOP_WATCH);
|
||||
stopWatch.stop();
|
||||
log.info("[afterCompletion][完成请求 URL({}) 耗时({} ms)]",
|
||||
request.getRequestURI(), stopWatch.getTotalTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印 Controller 方法路径
|
||||
*/
|
||||
private void printHandlerMethodPosition(HandlerMethod handlerMethod) {
|
||||
if (handlerMethod == null) {
|
||||
return;
|
||||
}
|
||||
Method method = handlerMethod.getMethod();
|
||||
Class<?> clazz = method.getDeclaringClass();
|
||||
try {
|
||||
// 获取 method 的 lineNumber
|
||||
List<String> clazzContents = FileUtil.readUtf8Lines(
|
||||
ResourceUtil.getResource(null, clazz).getPath().replace("/target/classes/", "/src/main/java/")
|
||||
+ clazz.getSimpleName() + ".java");
|
||||
Optional<Integer> lineNumber = IntStream.range(0, clazzContents.size())
|
||||
.filter(i -> clazzContents.get(i).contains(" " + method.getName() + "(")) // 简单匹配,不考虑方法重名
|
||||
.mapToObj(i -> i + 1) // 行号从 1 开始
|
||||
.findFirst();
|
||||
if (!lineNumber.isPresent()) {
|
||||
return;
|
||||
}
|
||||
// 打印结果
|
||||
System.out.printf("\tController 方法路径:%s(%s.java:%d)\n", clazz.getName(), clazz.getSimpleName(), lineNumber.get());
|
||||
} catch (Exception ignore) {
|
||||
// 忽略异常。原因:仅仅打印,非重要逻辑
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.base.annotation;
|
||||
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.handler.DesensitizationHandler;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.serializer.StringDesensitizeSerializer;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.handler.DesensitizationHandler;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.serializer.StringDesensitizeSerializer;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@ import cn.hutool.core.lang.Singleton;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.handler.DesensitizationHandler;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.BeanProperty;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.handler.DesensitizationHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.regex.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.regex.handler.EmailDesensitizationHandler;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.regex.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.regex.handler.DefaultRegexDesensitizationHandler;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.slider.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.handler.BankCardDesensitization;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.slider.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.handler.CarLicenseDesensitization;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.slider.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.handler.ChineseNameDesensitization;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.slider.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.handler.FixedPhoneDesensitization;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.slider.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.handler.IdCardDesensitization;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.slider.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.handler.MobileDesensitization;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.slider.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.handler.PasswordDesensitization;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.slider.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.handler.DefaultDesensitizationHandler;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@@ -63,8 +63,9 @@ public class ApiEncryptProperties {
|
||||
* 注意:
|
||||
* 1. 如果是【对称加密】时,它「后端」对应的是“密钥”。对应的,「前端」也对应的也是“密钥”。
|
||||
* 2. 如果是【非对称加密】时,它「后端」对应的是“公钥”。对应的,「前端」对应的是“私钥”。(重要!!!)
|
||||
*
|
||||
* 当前 system 模块密码加密方案不启用响应加密,因此该配置可为空。
|
||||
*/
|
||||
@NotEmpty(message = "响应的加密密钥不能为空")
|
||||
private String responseKey;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.njcn.msgpush.framework.common.enums.WebFilterOrderEnum;
|
||||
import com.njcn.msgpush.framework.encrypt.core.filter.ApiEncryptFilter;
|
||||
import com.njcn.msgpush.framework.web.config.WebProperties;
|
||||
import com.njcn.msgpush.framework.web.core.handler.GlobalExceptionHandler;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -24,9 +25,10 @@ public class MsgpushApiEncryptAutoConfiguration {
|
||||
public FilterRegistrationBean<ApiEncryptFilter> apiEncryptFilter(WebProperties webProperties,
|
||||
ApiEncryptProperties apiEncryptProperties,
|
||||
RequestMappingHandlerMapping requestMappingHandlerMapping,
|
||||
GlobalExceptionHandler globalExceptionHandler) {
|
||||
GlobalExceptionHandler globalExceptionHandler,
|
||||
ObjectMapper objectMapper) {
|
||||
ApiEncryptFilter filter = new ApiEncryptFilter(webProperties, apiEncryptProperties,
|
||||
requestMappingHandlerMapping, globalExceptionHandler);
|
||||
requestMappingHandlerMapping, globalExceptionHandler, objectMapper);
|
||||
return createFilterBean(filter, WebFilterOrderEnum.API_ENCRYPT_FILTER);
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,13 @@ public @interface ApiEncrypt {
|
||||
*/
|
||||
boolean request() default true;
|
||||
|
||||
/**
|
||||
* 需要解密的请求字段
|
||||
*
|
||||
* 仅在 request = true 时生效
|
||||
*/
|
||||
String[] requestFields() default {};
|
||||
|
||||
/**
|
||||
* 是否对响应结果进行加密,默认 true
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.njcn.msgpush.framework.encrypt.core.filter;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import cn.hutool.crypto.asymmetric.AsymmetricDecryptor;
|
||||
import cn.hutool.crypto.asymmetric.KeyType;
|
||||
import cn.hutool.crypto.symmetric.SymmetricDecryptor;
|
||||
@@ -14,6 +18,9 @@ import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
|
||||
|
||||
/**
|
||||
* 解密请求 {@link HttpServletRequestWrapper} 实现类
|
||||
@@ -25,16 +32,41 @@ public class ApiDecryptRequestWrapper extends HttpServletRequestWrapper {
|
||||
private final byte[] body;
|
||||
|
||||
public ApiDecryptRequestWrapper(HttpServletRequest request,
|
||||
ObjectMapper objectMapper,
|
||||
List<String> requestFields,
|
||||
SymmetricDecryptor symmetricDecryptor,
|
||||
AsymmetricDecryptor asymmetricDecryptor) throws IOException {
|
||||
super(request);
|
||||
// 读取 body,允许 HEX、BASE64 传输
|
||||
String requestBody = StrUtil.utf8Str(
|
||||
IoUtil.readBytes(request.getInputStream(), false));
|
||||
if (CollUtil.isEmpty(requestFields)) {
|
||||
throw invalidParamException("请求解密失败,请刷新页面后重试");
|
||||
}
|
||||
String requestBody = StrUtil.utf8Str(IoUtil.readBytes(request.getInputStream(), false));
|
||||
if (StrUtil.isBlank(requestBody)) {
|
||||
throw invalidParamException("请求解密失败,请刷新页面后重试");
|
||||
}
|
||||
|
||||
// 解密 body
|
||||
body = symmetricDecryptor != null ? symmetricDecryptor.decrypt(requestBody)
|
||||
: asymmetricDecryptor.decrypt(requestBody, KeyType.PrivateKey);
|
||||
JsonNode requestJson;
|
||||
try {
|
||||
requestJson = objectMapper.readTree(requestBody);
|
||||
} catch (Exception ex) {
|
||||
throw invalidParamException("请求解密失败,请刷新页面后重试");
|
||||
}
|
||||
if (!(requestJson instanceof ObjectNode requestObject)) {
|
||||
throw invalidParamException("请求解密失败,请刷新页面后重试");
|
||||
}
|
||||
|
||||
for (String requestField : requestFields) {
|
||||
JsonNode fieldNode = requestObject.get(requestField);
|
||||
if (fieldNode == null || fieldNode.isNull() || !fieldNode.isTextual() || StrUtil.isBlank(fieldNode.asText())) {
|
||||
throw invalidParamException("请求解密失败,请刷新页面后重试");
|
||||
}
|
||||
byte[] decryptedBytes = symmetricDecryptor != null
|
||||
? symmetricDecryptor.decrypt(fieldNode.asText())
|
||||
: asymmetricDecryptor.decrypt(fieldNode.asText(), KeyType.PrivateKey);
|
||||
requestObject.put(requestField, StrUtil.utf8Str(decryptedBytes));
|
||||
}
|
||||
|
||||
body = objectMapper.writeValueAsBytes(requestObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.hutool.crypto.asymmetric.AsymmetricDecryptor;
|
||||
import cn.hutool.crypto.asymmetric.AsymmetricEncryptor;
|
||||
import cn.hutool.crypto.symmetric.SymmetricDecryptor;
|
||||
import cn.hutool.crypto.symmetric.SymmetricEncryptor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.object.ObjectUtils;
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
@@ -26,6 +27,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
||||
import org.springframework.web.util.ServletRequestPathUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
|
||||
|
||||
@@ -43,12 +45,17 @@ import static com.njcn.msgpush.framework.common.exception.util.ServiceExceptionU
|
||||
@Slf4j
|
||||
public class ApiEncryptFilter extends ApiRequestFilter {
|
||||
|
||||
private static final String MISSING_ENCRYPT_HEADER_MESSAGE = "当前接口要求加密传输,请刷新页面后重试";
|
||||
private static final String DECRYPT_FAILED_MESSAGE = "请求解密失败,请刷新页面后重试";
|
||||
|
||||
private final ApiEncryptProperties apiEncryptProperties;
|
||||
|
||||
private final RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||
|
||||
private final GlobalExceptionHandler globalExceptionHandler;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final SymmetricDecryptor requestSymmetricDecryptor;
|
||||
private final AsymmetricDecryptor requestAsymmetricDecryptor;
|
||||
|
||||
@@ -58,21 +65,25 @@ public class ApiEncryptFilter extends ApiRequestFilter {
|
||||
public ApiEncryptFilter(WebProperties webProperties,
|
||||
ApiEncryptProperties apiEncryptProperties,
|
||||
RequestMappingHandlerMapping requestMappingHandlerMapping,
|
||||
GlobalExceptionHandler globalExceptionHandler) {
|
||||
GlobalExceptionHandler globalExceptionHandler,
|
||||
ObjectMapper objectMapper) {
|
||||
super(webProperties);
|
||||
this.apiEncryptProperties = apiEncryptProperties;
|
||||
this.requestMappingHandlerMapping = requestMappingHandlerMapping;
|
||||
this.globalExceptionHandler = globalExceptionHandler;
|
||||
this.objectMapper = objectMapper;
|
||||
if (StrUtil.equalsIgnoreCase(apiEncryptProperties.getAlgorithm(), "AES")) {
|
||||
this.requestSymmetricDecryptor = SecureUtil.aes(StrUtil.utf8Bytes(apiEncryptProperties.getRequestKey()));
|
||||
this.requestAsymmetricDecryptor = null;
|
||||
this.responseSymmetricEncryptor = SecureUtil.aes(StrUtil.utf8Bytes(apiEncryptProperties.getResponseKey()));
|
||||
this.responseSymmetricEncryptor = StrUtil.isNotBlank(apiEncryptProperties.getResponseKey())
|
||||
? SecureUtil.aes(StrUtil.utf8Bytes(apiEncryptProperties.getResponseKey())) : null;
|
||||
this.responseAsymmetricEncryptor = null;
|
||||
} else if (StrUtil.equalsIgnoreCase(apiEncryptProperties.getAlgorithm(), "RSA")) {
|
||||
this.requestSymmetricDecryptor = null;
|
||||
this.requestAsymmetricDecryptor = SecureUtil.rsa(apiEncryptProperties.getRequestKey(), null);
|
||||
this.responseSymmetricEncryptor = null;
|
||||
this.responseAsymmetricEncryptor = SecureUtil.rsa(null, apiEncryptProperties.getResponseKey());
|
||||
this.responseAsymmetricEncryptor = StrUtil.isNotBlank(apiEncryptProperties.getResponseKey())
|
||||
? SecureUtil.rsa(null, apiEncryptProperties.getResponseKey()) : null;
|
||||
} else {
|
||||
// 补充说明:如果要支持 SM2、SM4 等算法,可在此处增加对应实例的创建,并添加相应的 Maven 依赖即可。
|
||||
throw new IllegalArgumentException("不支持的加密算法:" + apiEncryptProperties.getAlgorithm());
|
||||
@@ -86,9 +97,10 @@ public class ApiEncryptFilter extends ApiRequestFilter {
|
||||
// 获取 @ApiEncrypt 注解
|
||||
ApiEncrypt apiEncrypt = getApiEncrypt(request);
|
||||
boolean requestEnable = apiEncrypt != null && apiEncrypt.request();
|
||||
boolean responseEnable = apiEncrypt != null && apiEncrypt.response();
|
||||
boolean responseEnable = apiEncrypt != null && apiEncrypt.response()
|
||||
&& (responseSymmetricEncryptor != null || responseAsymmetricEncryptor != null);
|
||||
String encryptHeader = request.getHeader(apiEncryptProperties.getHeader());
|
||||
if (!requestEnable && !responseEnable && StrUtil.isBlank(encryptHeader)) {
|
||||
if (!requestEnable && !responseEnable) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
@@ -97,13 +109,19 @@ public class ApiEncryptFilter extends ApiRequestFilter {
|
||||
if (ObjectUtils.equalsAny(HttpMethod.valueOf(request.getMethod()),
|
||||
HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE)) {
|
||||
try {
|
||||
if (StrUtil.isNotBlank(encryptHeader)) {
|
||||
request = new ApiDecryptRequestWrapper(request,
|
||||
if (requestEnable) {
|
||||
if (StrUtil.isBlank(encryptHeader)) {
|
||||
throw invalidParamException(MISSING_ENCRYPT_HEADER_MESSAGE);
|
||||
}
|
||||
request = new ApiDecryptRequestWrapper(request, objectMapper,
|
||||
Arrays.asList(apiEncrypt.requestFields()),
|
||||
requestSymmetricDecryptor, requestAsymmetricDecryptor);
|
||||
} else if (requestEnable) {
|
||||
throw invalidParamException("请求未包含加密标头,请检查是否正确配置了加密标头");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (!(ex instanceof com.njcn.msgpush.framework.common.exception.ServiceException)
|
||||
|| !StrUtil.equals(ex.getMessage(), MISSING_ENCRYPT_HEADER_MESSAGE)) {
|
||||
ex = invalidParamException(DECRYPT_FAILED_MESSAGE);
|
||||
}
|
||||
CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, ex);
|
||||
ServletUtils.writeJSON(response, result);
|
||||
return;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package com.njcn.msgpush.framework.jackson.config;
|
||||
|
||||
import com.njcn.msgpush.framework.common.util.json.JsonUtils;
|
||||
import com.njcn.msgpush.framework.common.util.json.databind.NumberSerializer;
|
||||
import com.njcn.msgpush.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
|
||||
import com.njcn.msgpush.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
@@ -11,6 +7,10 @@ import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import com.njcn.msgpush.framework.common.util.json.JsonUtils;
|
||||
import com.njcn.msgpush.framework.common.util.json.databind.NumberSerializer;
|
||||
import com.njcn.msgpush.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
|
||||
import com.njcn.msgpush.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Web 框架,全局异常、API 日志等
|
||||
*/
|
||||
package com.njcn.msgpush.framework;
|
||||
@@ -6,7 +6,6 @@ import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Contact;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
import io.swagger.v3.oas.models.media.IntegerSchema;
|
||||
import io.swagger.v3.oas.models.media.StringSchema;
|
||||
import io.swagger.v3.oas.models.parameters.Parameter;
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
@@ -34,41 +33,24 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
/**
|
||||
* Swagger 自动配置类,基于 OpenAPI + Springdoc 实现。
|
||||
*
|
||||
* 友情提示:
|
||||
* 1. Springdoc 文档地址:<a href="https://github.com/springdoc/springdoc-openapi">仓库</a>
|
||||
* 2. Swagger 规范,于 2015 更名为 OpenAPI 规范,本质是一个东西
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
@AutoConfiguration(before = Knife4jAutoConfiguration.class) // before 原因,保证覆写的 Knife4jOpenApiCustomizer 先生效!相关 https://github.com/YunaiV/ruoyi-vue-pro/issues/954 讨论
|
||||
@AutoConfiguration(before = Knife4jAutoConfiguration.class)
|
||||
@ConditionalOnClass({OpenAPI.class})
|
||||
@EnableConfigurationProperties(SwaggerProperties.class)
|
||||
@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true) // 设置为 false 时,禁用
|
||||
@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
@Import(Knife4jOpenApiCustomizer.class)
|
||||
public class MsgpushSwaggerAutoConfiguration {
|
||||
|
||||
// ========== 全局 OpenAPI 配置 ==========
|
||||
|
||||
@Bean
|
||||
public OpenAPI createApi(SwaggerProperties properties) {
|
||||
Map<String, SecurityScheme> securitySchemas = buildSecuritySchemes();
|
||||
OpenAPI openAPI = new OpenAPI()
|
||||
// 接口信息
|
||||
.info(buildInfo(properties))
|
||||
// 接口安全配置
|
||||
.components(new Components().securitySchemes(securitySchemas))
|
||||
.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
|
||||
securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key)));
|
||||
return openAPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* API 摘要信息
|
||||
*/
|
||||
private Info buildInfo(SwaggerProperties properties) {
|
||||
return new Info()
|
||||
.title(properties.getTitle())
|
||||
@@ -78,24 +60,18 @@ public class MsgpushSwaggerAutoConfiguration {
|
||||
.license(new License().name(properties.getLicense()).url(properties.getLicenseUrl()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全模式,这里配置通过请求头 Authorization 传递 token 参数
|
||||
*/
|
||||
private Map<String, SecurityScheme> buildSecuritySchemes() {
|
||||
Map<String, SecurityScheme> securitySchemes = new HashMap<>();
|
||||
SecurityScheme securityScheme = new SecurityScheme()
|
||||
.type(SecurityScheme.Type.APIKEY) // 类型
|
||||
.name(HttpHeaders.AUTHORIZATION) // 请求头的 name
|
||||
.in(SecurityScheme.In.HEADER); // token 所在位置
|
||||
.type(SecurityScheme.Type.APIKEY)
|
||||
.name(HttpHeaders.AUTHORIZATION)
|
||||
.in(SecurityScheme.In.HEADER);
|
||||
securitySchemes.put(HttpHeaders.AUTHORIZATION, securityScheme);
|
||||
return securitySchemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 OpenAPI 处理器
|
||||
*/
|
||||
@Bean
|
||||
@Primary // 目的:以我们创建的 OpenAPIService Bean 为主,避免一键改包后,启动报错!
|
||||
@Primary
|
||||
public OpenAPIService openApiBuilder(Optional<OpenAPI> openAPI,
|
||||
SecurityService securityParser,
|
||||
SpringDocConfigProperties springDocConfigProperties,
|
||||
@@ -107,11 +83,6 @@ public class MsgpushSwaggerAutoConfiguration {
|
||||
propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider);
|
||||
}
|
||||
|
||||
// ========== 分组 OpenAPI 配置 ==========
|
||||
|
||||
/**
|
||||
* 所有模块的 API 分组
|
||||
*/
|
||||
@Bean
|
||||
public GroupedOpenApi allGroupedOpenApi() {
|
||||
return buildGroupedOpenApi("all", "");
|
||||
@@ -131,43 +102,24 @@ public class MsgpushSwaggerAutoConfiguration {
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 构建 Authorization 认证请求头参数
|
||||
*
|
||||
* 解决 Knife4j <a href="https://gitee.com/xiaoym/knife4j/issues/I69QBU">Authorize 未生效,请求header里未包含参数</a>
|
||||
*
|
||||
* @return 认证参数
|
||||
*/
|
||||
private static Parameter buildSecurityHeaderParameter() {
|
||||
return new Parameter()
|
||||
.name(HttpHeaders.AUTHORIZATION) // header 名
|
||||
.description("认证 Token") // 描述
|
||||
.in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header
|
||||
.schema(new StringSchema()._default("Bearer test1").description("认证 Token")); // 默认:使用用户编号为 1
|
||||
.name(HttpHeaders.AUTHORIZATION)
|
||||
.description("认证 Token")
|
||||
.in(String.valueOf(SecurityScheme.In.HEADER))
|
||||
.schema(new StringSchema()._default("Bearer test1")
|
||||
.name(HttpHeaders.AUTHORIZATION)
|
||||
.description("认证 Token"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心:自定义OperationId生成规则,组合「类名前缀 + 方法名」
|
||||
*
|
||||
* @see <a href="https://github.com/YunaiV/ruoyi-vue-pro/issues/957">app-api 前缀不生效,都是使用 admin-api</a>
|
||||
*/
|
||||
private static OperationCustomizer buildOperationIdCustomizer() {
|
||||
return (operation, handlerMethod) -> {
|
||||
// 1. 获取控制器类名(如 UserController)
|
||||
String className = handlerMethod.getBeanType().getSimpleName();
|
||||
// 2. 提取类名前缀(去除 Controller 后缀,如 UserController -> User)
|
||||
String classPrefix = className.replaceAll("Controller$", "");
|
||||
// 3. 获取方法名(如 list)
|
||||
String methodName = handlerMethod.getMethod().getName();
|
||||
// 4. 组合生成 operationId(如 User_list)
|
||||
String operationId = classPrefix + "_" + methodName;
|
||||
// 5. 设置自定义 operationId
|
||||
operation.setOperationId(operationId);
|
||||
operation.setOperationId(classPrefix + "_" + methodName);
|
||||
return operation;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.njcn.msgpush.framework.swagger.config;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
|
||||
/**
|
||||
* Swagger 配置属性
|
||||
*
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
package com.njcn.msgpush.framework.web.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.ApiErrorLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.enums.WebFilterOrderEnum;
|
||||
import com.njcn.msgpush.framework.web.core.filter.CacheRequestBodyFilter;
|
||||
import com.njcn.msgpush.framework.web.core.filter.DemoFilter;
|
||||
import com.njcn.msgpush.framework.web.core.handler.GlobalExceptionHandler;
|
||||
import com.njcn.msgpush.framework.web.core.handler.GlobalResponseBodyHandler;
|
||||
import com.njcn.msgpush.framework.web.core.util.WebFrameworkUtils;
|
||||
import com.google.common.collect.Maps;
|
||||
import jakarta.servlet.Filter;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@@ -133,12 +131,6 @@ public class MsgpushWebAutoConfiguration {
|
||||
/**
|
||||
* 创建 DemoFilter Bean,演示模式
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "msgpush.demo", havingValue = "true")
|
||||
public FilterRegistrationBean<DemoFilter> demoFilter() {
|
||||
return createFilterBean(new DemoFilter(), WebFilterOrderEnum.DEMO_FILTER);
|
||||
}
|
||||
|
||||
public static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
|
||||
FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
|
||||
bean.setOrder(order);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.njcn.msgpush.framework.web.config;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -7,10 +10,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
@ConfigurationProperties(prefix = "msgpush.web")
|
||||
@Validated
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.njcn.msgpush.framework.web.core.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.web.config.WebProperties;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 过滤 /admin-api、/app-api 等 API 请求的过滤器
|
||||
*
|
||||
|
||||
@@ -2,12 +2,12 @@ package com.njcn.msgpush.framework.web.core.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.njcn.msgpush.framework.web.core.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
import com.njcn.msgpush.framework.web.core.util.WebFrameworkUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import static com.njcn.msgpush.framework.common.exception.enums.GlobalErrorCodeConstants.DEMO_DENY;
|
||||
|
||||
/**
|
||||
* 演示 Filter,禁止用户发起写操作,避免影响测试数据
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
public class DemoFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected boolean shouldNotFilter(HttpServletRequest request) {
|
||||
String method = request.getMethod();
|
||||
return !StrUtil.equalsAnyIgnoreCase(method, "POST", "PUT", "DELETE") // 写操作时,不进行过滤率
|
||||
|| WebFrameworkUtils.getLoginUserId(request) == null; // 非登录用户时,不进行过滤
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
|
||||
// 直接返回 DEMO_DENY 的结果。即,请求不继续
|
||||
ServletUtils.writeJSON(response, CommonResult.error(DEMO_DENY));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,8 +5,10 @@ import cn.hutool.core.exceptions.ExceptionUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.msgpush.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
|
||||
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.ApiErrorLogCommonApi;
|
||||
import com.njcn.msgpush.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
|
||||
import com.njcn.msgpush.framework.common.exception.ServiceException;
|
||||
import com.njcn.msgpush.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
@@ -15,8 +17,6 @@ import com.njcn.msgpush.framework.common.util.json.JsonUtils;
|
||||
import com.njcn.msgpush.framework.common.util.monitor.TracerUtils;
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
import com.njcn.msgpush.framework.web.core.util.WebFrameworkUtils;
|
||||
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
@@ -393,61 +393,7 @@ public class GlobalExceptionHandler {
|
||||
if (!message.contains("doesn't exist")) {
|
||||
return null;
|
||||
}
|
||||
// 1. 数据报表
|
||||
if (message.contains("report_")) {
|
||||
log.error("[报表模块 msgpush-module-report - 表结构未导入][参考 https://cloud.iocoder.cn/report/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[报表模块 msgpush-module-report - 表结构未导入][参考 https://cloud.iocoder.cn/report/ 开启]");
|
||||
}
|
||||
// 2. 工作流
|
||||
if (message.contains("bpm_")) {
|
||||
log.error("[工作流模块 msgpush-module-bpm - 表结构未导入][参考 https://cloud.iocoder.cn/bpm/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[工作流模块 msgpush-module-bpm - 表结构未导入][参考 https://cloud.iocoder.cn/bpm/ 开启]");
|
||||
}
|
||||
// 3. 微信公众号
|
||||
if (message.contains("mp_")) {
|
||||
log.error("[微信公众号 msgpush-module-mp - 表结构未导入][参考 https://cloud.iocoder.cn/mp/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[微信公众号 msgpush-module-mp - 表结构未导入][参考 https://cloud.iocoder.cn/mp/build/ 开启]");
|
||||
}
|
||||
// 4. 商城系统
|
||||
if (StrUtil.containsAny(message, "product_", "promotion_", "trade_")) {
|
||||
log.error("[商城系统 msgpush-module-mall - 已禁用][参考 https://cloud.iocoder.cn/mall/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[商城系统 msgpush-module-mall - 已禁用][参考 https://cloud.iocoder.cn/mall/build/ 开启]");
|
||||
}
|
||||
// 5. ERP 系统
|
||||
if (message.contains("erp_")) {
|
||||
log.error("[ERP 系统 msgpush-module-erp - 表结构未导入][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[ERP 系统 msgpush-module-erp - 表结构未导入][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
|
||||
}
|
||||
// 6. CRM 系统
|
||||
if (message.contains("crm_")) {
|
||||
log.error("[CRM 系统 msgpush-module-crm - 表结构未导入][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[CRM 系统 msgpush-module-crm - 表结构未导入][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
|
||||
}
|
||||
// 7. 支付平台
|
||||
if (message.contains("pay_")) {
|
||||
log.error("[支付模块 msgpush-module-pay - 表结构未导入][参考 https://cloud.iocoder.cn/pay/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[支付模块 msgpush-module-pay - 表结构未导入][参考 https://cloud.iocoder.cn/pay/build/ 开启]");
|
||||
}
|
||||
// 8. AI 大模型
|
||||
if (message.contains("ai_")) {
|
||||
log.error("[AI 大模型 msgpush-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[AI 大模型 msgpush-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
|
||||
}
|
||||
// 9. IoT 物联网
|
||||
if (message.contains("iot_")) {
|
||||
log.error("[IoT 物联网 msgpush-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[IoT 物联网 msgpush-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
|
||||
}
|
||||
return null;
|
||||
return CommonResult.error(TABLE_NOT_EXISTS.getCode(), TABLE_NOT_EXISTS.getMsg());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,37 +1,23 @@
|
||||
package com.njcn.msgpush.framework.web.core.util;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.njcn.msgpush.framework.common.enums.RpcConstants;
|
||||
import com.njcn.msgpush.framework.common.enums.TerminalEnum;
|
||||
import com.njcn.msgpush.framework.common.enums.UserTypeEnum;
|
||||
import com.njcn.msgpush.framework.common.pojo.CommonResult;
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
import com.njcn.msgpush.framework.web.config.WebProperties;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 专属于 web 包的工具类
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
public class WebFrameworkUtils {
|
||||
|
||||
private static final String REQUEST_ATTRIBUTE_LOGIN_USER_ID = "login_user_id";
|
||||
private static final String REQUEST_ATTRIBUTE_LOGIN_USER_TYPE = "login_user_type";
|
||||
|
||||
private static final String REQUEST_ATTRIBUTE_COMMON_RESULT = "common_result";
|
||||
|
||||
/**
|
||||
* 终端的 Header
|
||||
*
|
||||
* @see com.njcn.msgpush.framework.common.enums.TerminalEnum
|
||||
*/
|
||||
public static final String HEADER_TERMINAL = "terminal";
|
||||
|
||||
private static WebProperties properties;
|
||||
@@ -40,30 +26,14 @@ public class WebFrameworkUtils {
|
||||
WebFrameworkUtils.properties = webProperties;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static void setLoginUserId(ServletRequest request, Long userId) {
|
||||
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户类型
|
||||
*
|
||||
* @param request 请求
|
||||
* @param userType 用户类型
|
||||
*/
|
||||
public static void setLoginUserType(ServletRequest request, Integer userType) {
|
||||
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE, userType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前用户的编号,从请求中
|
||||
* 注意:该方法仅限于 framework 框架使用!!!
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 用户编号
|
||||
*/
|
||||
public static Long getLoginUserId(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return null;
|
||||
@@ -71,23 +41,14 @@ public class WebFrameworkUtils {
|
||||
return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前用户的类型
|
||||
* 注意:该方法仅限于 web 相关的 framework 组件使用!!!
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 用户编号
|
||||
*/
|
||||
public static Integer getLoginUserType(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
// 1. 优先,从 Attribute 中获取
|
||||
Integer userType = (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE);
|
||||
if (userType != null) {
|
||||
return userType;
|
||||
}
|
||||
// 2. 其次,基于 URL 前缀的约定
|
||||
if (request.getServletPath().startsWith(properties.getAdminApi().getPrefix())) {
|
||||
return UserTypeEnum.ADMIN.getValue();
|
||||
}
|
||||
@@ -98,13 +59,11 @@ public class WebFrameworkUtils {
|
||||
}
|
||||
|
||||
public static Integer getLoginUserType() {
|
||||
HttpServletRequest request = getRequest();
|
||||
return getLoginUserType(request);
|
||||
return getLoginUserType(getRequest());
|
||||
}
|
||||
|
||||
public static Long getLoginUserId() {
|
||||
HttpServletRequest request = getRequest();
|
||||
return getLoginUserId(request);
|
||||
return getLoginUserId(getRequest());
|
||||
}
|
||||
|
||||
public static Integer getTerminal() {
|
||||
@@ -134,24 +93,10 @@ public class WebFrameworkUtils {
|
||||
return servletRequestAttributes.getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为 RPC 请求
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 是否为 RPC 请求
|
||||
*/
|
||||
public static boolean isRpcRequest(HttpServletRequest request) {
|
||||
return request.getRequestURI().startsWith(RpcConstants.RPC_API_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为 RPC 请求
|
||||
*
|
||||
* 约定大于配置,只要以 Api 结尾,都认为是 RPC 接口
|
||||
*
|
||||
* @param className 类名
|
||||
* @return 是否为 RPC 请求
|
||||
*/
|
||||
public static boolean isRpcRequest(String className) {
|
||||
return className.endsWith("Api");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.njcn.msgpush.framework.xss.core.clean.JsoupXssCleaner;
|
||||
import com.njcn.msgpush.framework.xss.core.clean.XssCleaner;
|
||||
import com.njcn.msgpush.framework.xss.core.filter.XssFilter;
|
||||
import com.njcn.msgpush.framework.xss.core.json.XssStringJsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
||||
@@ -2,14 +2,14 @@ package com.njcn.msgpush.framework.xss.core.filter;
|
||||
|
||||
import com.njcn.msgpush.framework.xss.config.XssProperties;
|
||||
import com.njcn.msgpush.framework.xss.core.clean.XssCleaner;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.njcn.msgpush.framework.xss.core.filter;
|
||||
|
||||
import com.njcn.msgpush.framework.xss.core.clean.XssCleaner;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.njcn.msgpush.framework.xss.core.json;
|
||||
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
import com.njcn.msgpush.framework.xss.config.XssProperties;
|
||||
import com.njcn.msgpush.framework.xss.core.clean.XssCleaner;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
|
||||
import com.njcn.msgpush.framework.common.util.servlet.ServletUtils;
|
||||
import com.njcn.msgpush.framework.xss.config.XssProperties;
|
||||
import com.njcn.msgpush.framework.xss.core.clean.XssCleaner;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -5,4 +5,4 @@ com.njcn.msgpush.framework.web.config.MsgpushWebAutoConfiguration
|
||||
com.njcn.msgpush.framework.apilog.config.MsgpushApiLogRpcAutoConfiguration
|
||||
com.njcn.msgpush.framework.xss.config.MsgpushXssAutoConfiguration
|
||||
com.njcn.msgpush.framework.banner.config.MsgpushBannerAutoConfiguration
|
||||
com.njcn.msgpush.framework.encrypt.config.MsgpushApiEncryptAutoConfiguration
|
||||
com.njcn.msgpush.framework.encrypt.config.MsgpushApiEncryptAutoConfiguration
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
灿能源码 http://www.iocoder.cn
|
||||
Application Version: ${msgpush.info.version}
|
||||
Spring Boot Version: ${spring-boot.version}
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core;
|
||||
|
||||
import com.njcn.msgpush.framework.common.util.json.JsonUtils;
|
||||
import com.njcn.msgpush.framework.desensitize.core.regex.annotation.EmailDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.regex.annotation.RegexDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.annotation.Address;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.annotation.BankCardDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.annotation.CarLicenseDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.annotation.ChineseNameDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.annotation.FixedPhoneDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.annotation.IdCardDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.annotation.PasswordDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.annotation.MobileDesensitize;
|
||||
import com.njcn.msgpush.framework.desensitize.core.slider.annotation.SliderDesensitize;
|
||||
import lombok.Data;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* {@link DesensitizeTest} 的单元测试
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class DesensitizeTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// 准备参数
|
||||
DesensitizeDemo desensitizeDemo = new DesensitizeDemo();
|
||||
desensitizeDemo.setNickname("灿能源码");
|
||||
desensitizeDemo.setBankCard("9988002866797031");
|
||||
desensitizeDemo.setCarLicense("粤A66666");
|
||||
desensitizeDemo.setFixedPhone("01086551122");
|
||||
desensitizeDemo.setIdCard("530321199204074611");
|
||||
desensitizeDemo.setPassword("123456");
|
||||
desensitizeDemo.setPhoneNumber("13248765917");
|
||||
desensitizeDemo.setSlider1("ABCDEFG");
|
||||
desensitizeDemo.setSlider2("ABCDEFG");
|
||||
desensitizeDemo.setSlider3("ABCDEFG");
|
||||
desensitizeDemo.setEmail("1@email.com");
|
||||
desensitizeDemo.setRegex("你好,我是灿能源码");
|
||||
desensitizeDemo.setAddress("北京市海淀区上地十街10号");
|
||||
desensitizeDemo.setOrigin("灿能源码");
|
||||
|
||||
// 调用
|
||||
DesensitizeDemo d = JsonUtils.parseObject(JsonUtils.toJsonString(desensitizeDemo), DesensitizeDemo.class);
|
||||
// 断言
|
||||
assertNotNull(d);
|
||||
assertEquals("芋***", d.getNickname());
|
||||
assertEquals("998800********31", d.getBankCard());
|
||||
assertEquals("粤A6***6", d.getCarLicense());
|
||||
assertEquals("0108*****22", d.getFixedPhone());
|
||||
assertEquals("530321**********11", d.getIdCard());
|
||||
assertEquals("******", d.getPassword());
|
||||
assertEquals("132****5917", d.getPhoneNumber());
|
||||
assertEquals("#######", d.getSlider1());
|
||||
assertEquals("ABC*EFG", d.getSlider2());
|
||||
assertEquals("*******", d.getSlider3());
|
||||
assertEquals("1****@email.com", d.getEmail());
|
||||
assertEquals("你好,我是*", d.getRegex());
|
||||
assertEquals("北京市海淀区上地十街10号*", d.getAddress());
|
||||
assertEquals("灿能源码", d.getOrigin());
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DesensitizeDemo {
|
||||
|
||||
@ChineseNameDesensitize
|
||||
private String nickname;
|
||||
@BankCardDesensitize
|
||||
private String bankCard;
|
||||
@CarLicenseDesensitize
|
||||
private String carLicense;
|
||||
@FixedPhoneDesensitize
|
||||
private String fixedPhone;
|
||||
@IdCardDesensitize
|
||||
private String idCard;
|
||||
@PasswordDesensitize
|
||||
private String password;
|
||||
@MobileDesensitize
|
||||
private String phoneNumber;
|
||||
@SliderDesensitize(prefixKeep = 6, suffixKeep = 1, replacer = "#")
|
||||
private String slider1;
|
||||
@SliderDesensitize(prefixKeep = 3, suffixKeep = 3)
|
||||
private String slider2;
|
||||
@SliderDesensitize(prefixKeep = 10)
|
||||
private String slider3;
|
||||
@EmailDesensitize
|
||||
private String email;
|
||||
@RegexDesensitize(regex = "灿能源码", replacer = "*")
|
||||
private String regex;
|
||||
@Address
|
||||
private String address;
|
||||
private String origin;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.annotation;
|
||||
|
||||
import com.njcn.msgpush.framework.desensitize.core.DesensitizeTest;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.annotation.DesensitizeBy;
|
||||
import com.njcn.msgpush.framework.desensitize.core.handler.AddressHandler;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 地址
|
||||
*
|
||||
* 用于 {@link DesensitizeTest} 测试使用
|
||||
*
|
||||
* @author gaibu
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@JacksonAnnotationsInside
|
||||
@DesensitizeBy(handler = AddressHandler.class)
|
||||
public @interface Address {
|
||||
|
||||
String replacer() default "*";
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.njcn.msgpush.framework.desensitize.core.handler;
|
||||
|
||||
import com.njcn.msgpush.framework.desensitize.core.DesensitizeTest;
|
||||
import com.njcn.msgpush.framework.desensitize.core.base.handler.DesensitizationHandler;
|
||||
import com.njcn.msgpush.framework.desensitize.core.annotation.Address;
|
||||
|
||||
/**
|
||||
* {@link Address} 的脱敏处理器
|
||||
*
|
||||
* 用于 {@link DesensitizeTest} 测试使用
|
||||
*/
|
||||
public class AddressHandler implements DesensitizationHandler<Address> {
|
||||
|
||||
@Override
|
||||
public String desensitize(String origin, Address annotation) {
|
||||
return origin + annotation.replacer();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package com.njcn.msgpush.framework.encrypt;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.asymmetric.AsymmetricAlgorithm;
|
||||
import cn.hutool.crypto.asymmetric.KeyType;
|
||||
import cn.hutool.crypto.asymmetric.RSA;
|
||||
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 各种 API 加解密的测试类:不是单测,而是方便大家生成密钥、加密、解密等操作。
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
@SuppressWarnings("ConstantValue")
|
||||
public class ApiEncryptTest {
|
||||
|
||||
@Test
|
||||
public void testGenerateAsymmetric() {
|
||||
String asymmetricAlgorithm = AsymmetricAlgorithm.RSA.getValue();
|
||||
// String asymmetricAlgorithm = "SM2";
|
||||
// String asymmetricAlgorithm = SM4.ALGORITHM_NAME;
|
||||
// String asymmetricAlgorithm = SymmetricAlgorithm.AES.getValue();
|
||||
String requestClientKey = null;
|
||||
String requestServerKey = null;
|
||||
String responseClientKey = null;
|
||||
String responseServerKey = null;
|
||||
if (Objects.equals(asymmetricAlgorithm, AsymmetricAlgorithm.RSA.getValue())) {
|
||||
// 请求的密钥
|
||||
RSA requestRsa = SecureUtil.rsa();
|
||||
requestClientKey = requestRsa.getPublicKeyBase64();
|
||||
requestServerKey = requestRsa.getPrivateKeyBase64();
|
||||
// 响应的密钥
|
||||
RSA responseRsa = new RSA();
|
||||
responseClientKey = responseRsa.getPrivateKeyBase64();
|
||||
responseServerKey = responseRsa.getPublicKeyBase64();
|
||||
} else if (Objects.equals(asymmetricAlgorithm, SymmetricAlgorithm.AES.getValue())) {
|
||||
// AES 密钥可选 32、24、16 位
|
||||
// 请求的密钥(前后端密钥一致)
|
||||
requestClientKey = RandomUtil.randomNumbers(32);
|
||||
requestServerKey = requestClientKey;
|
||||
// 响应的密钥(前后端密钥一致)
|
||||
responseClientKey = RandomUtil.randomNumbers(32);
|
||||
responseServerKey = responseClientKey;
|
||||
}
|
||||
|
||||
// 打印结果
|
||||
System.out.println("requestClientKey = " + requestClientKey);
|
||||
System.out.println("requestServerKey = " + requestServerKey);
|
||||
System.out.println("responseClientKey = " + responseClientKey);
|
||||
System.out.println("responseServerKey = " + responseServerKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncrypt_aes() {
|
||||
String key = "52549111389893486934626385991395";
|
||||
String body = "{\n" +
|
||||
" \"username\": \"admin\",\n" +
|
||||
" \"password\": \"admin123\",\n" +
|
||||
" \"uuid\": \"3acd87a09a4f48fb9118333780e94883\",\n" +
|
||||
" \"code\": \"1024\"\n" +
|
||||
"}";
|
||||
String encrypt = SecureUtil.aes(StrUtil.utf8Bytes(key))
|
||||
.encryptBase64(body);
|
||||
System.out.println("encrypt = " + encrypt);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncrypt_rsa() {
|
||||
String key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCls2rIpnGdYnLFgz1XU13GbNQ5DloyPpvW00FPGjqn5Z6JpK+kDtVlnkhwR87iRrE5Vf2WNqRX6vzbLSgveIQY8e8oqGCb829myjf1MuI+ZzN4ghf/7tEYhZJGPI9AbfxFqBUzm+kR3/HByAI22GLT96WM26QiMK8n3tIP/yiLswIDAQAB";
|
||||
String body = "{\n" +
|
||||
" \"username\": \"admin\",\n" +
|
||||
" \"password\": \"admin123\",\n" +
|
||||
" \"uuid\": \"3acd87a09a4f48fb9118333780e94883\",\n" +
|
||||
" \"code\": \"1024\"\n" +
|
||||
"}";
|
||||
String encrypt = SecureUtil.rsa(null, key)
|
||||
.encryptBase64(body, KeyType.PublicKey);
|
||||
System.out.println("encrypt = " + encrypt);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user