From 10b5b0e82a2125ee90ff036aed877d2e6cadfe51 Mon Sep 17 00:00:00 2001 From: wdhcr Date: Wed, 21 Jun 2023 22:57:32 +0800 Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E5=90=88=E5=89=8D=E7=AB=AF=E4=BD=BF?= =?UTF-8?q?=E7=94=A8jsencrypt=E5=AE=9E=E7=8E=B0=E6=8E=A5=E5=8F=A3=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=8A=A0=E5=AF=86=E5=8A=9F=E8=83=BD,=20=E5=8F=AF?= =?UTF-8?q?=E5=9C=A8application.yml=E4=B8=AD=E5=85=A8=E5=B1=80=E5=BC=80?= =?UTF-8?q?=E5=90=AF,=20=E4=B9=9F=E5=8F=AF=E9=80=9A=E8=BF=87=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=B3=A8=E8=A7=A3@ApiDecrypt=E5=AF=B9?= =?UTF-8?q?=E5=8D=95=E7=8B=AC=E6=8E=A5=E5=8F=A3=E5=BC=80=E5=90=AF.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-admin/pom.xml | 6 + .../src/main/resources/application.yml | 10 ++ ruoyi-common/pom.xml | 1 + ruoyi-common/ruoyi-common-bom/pom.xml | 7 ++ ruoyi-common/ruoyi-common-cryptapi/pom.xml | 34 ++++++ .../cryptapi/annotation/ApiDecrypt.java | 15 +++ .../cryptapi/config/ApiDecryptConfig.java | 47 ++++++++ .../dromara/cryptapi/core/AesEncryptor.java | 57 ++++++++++ .../dromara/cryptapi/core/EncryptContext.java | 35 ++++++ .../dromara/cryptapi/core/RsaEncryptor.java | 52 +++++++++ .../dromara/cryptapi/enums/EncodeType.java | 13 +++ .../dromara/cryptapi/filter/CryptoFilter.java | 54 +++++++++ .../filter/DecryptRequestBodyWrapper.java | 103 ++++++++++++++++++ .../cryptapi/handler/DecryptUrlHandler.java | 55 ++++++++++ .../properties/ApiDecryptProperties.java | 34 ++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + 16 files changed, 524 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-cryptapi/pom.xml create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/annotation/ApiDecrypt.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/config/ApiDecryptConfig.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/AesEncryptor.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/EncryptContext.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/RsaEncryptor.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/enums/EncodeType.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/CryptoFilter.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/DecryptRequestBodyWrapper.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/handler/DecryptUrlHandler.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/properties/ApiDecryptProperties.java create mode 100644 ruoyi-common/ruoyi-common-cryptapi/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 39731b1a..3d121c05 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -87,6 +87,12 @@ JustAuth + + + org.dromara + ruoyi-common-cryptapi + + diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index fcc18650..878a9c30 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -173,6 +173,16 @@ mybatis-encryptor: publicKey: privateKey: +# api接口加密 +api-decrypt: + # 是否开启全局接口加密 + enable: false + # AES 加密头标识 + headerFlag: AES + # 公私钥 非对称算法的公私钥 如:SM2,RSA + publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== + privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= + springdoc: api-docs: # 是否开启接口文档 diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 45493d3e..e77ea237 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -33,6 +33,7 @@ ruoyi-common-encrypt ruoyi-common-tenant ruoyi-common-websocket + ruoyi-common-cryptapi ruoyi-common diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index 93d11897..5014954d 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -171,6 +171,13 @@ ruoyi-common-websocket ${revision} + + + + org.dromara + ruoyi-common-cryptapi + ${revision} + diff --git a/ruoyi-common/ruoyi-common-cryptapi/pom.xml b/ruoyi-common/ruoyi-common-cryptapi/pom.xml new file mode 100644 index 00000000..ee0c5777 --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/pom.xml @@ -0,0 +1,34 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-cryptapi + + + ruoyi-common-cryptapi 接口请求参数加密模块 + + + + + + org.dromara + ruoyi-common-core + + + cn.hutool + hutool-crypto + + + org.springframework + spring-webmvc + + + + diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/annotation/ApiDecrypt.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/annotation/ApiDecrypt.java new file mode 100644 index 00000000..2e2bdee7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/annotation/ApiDecrypt.java @@ -0,0 +1,15 @@ +package org.dromara.cryptapi.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 当标有当前注解的接口,接口穿参为加密字符串,进行解密后为dto对象, 不影响后续参数校验。 + * @author wdhcr + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ApiDecrypt { +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/config/ApiDecryptConfig.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/config/ApiDecryptConfig.java new file mode 100644 index 00000000..c74339b8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/config/ApiDecryptConfig.java @@ -0,0 +1,47 @@ +package org.dromara.cryptapi.config; + +import cn.hutool.core.collection.CollectionUtil; +import jakarta.servlet.DispatcherType; +import lombok.RequiredArgsConstructor; +import org.dromara.cryptapi.filter.CryptoFilter; +import org.dromara.cryptapi.handler.DecryptUrlHandler; +import org.dromara.cryptapi.properties.ApiDecryptProperties; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; + +import java.util.HashMap; +import java.util.List; + +@AutoConfiguration +@RequiredArgsConstructor +@EnableConfigurationProperties(ApiDecryptProperties.class) +public class ApiDecryptConfig { + + private final DecryptUrlHandler decryptUrlHandler; + + private final ApiDecryptProperties apiDecryptProperties; + + @Bean + public FilterRegistrationBean cryptoFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new CryptoFilter()); + List urls = decryptUrlHandler.getUrls(); + if (CollectionUtil.isNotEmpty(urls) || apiDecryptProperties.getEnable()) { + registration.setEnabled(true); + registration.addUrlPatterns(urls.toArray(new String[0])); + } else { + registration.setEnabled(false); + } + registration.setName("cryptoFilter"); + HashMap param = new HashMap<>(); + param.put(CryptoFilter.CRYPTO_PUBLIC_KEY, apiDecryptProperties.getPublicKey()); + param.put(CryptoFilter.CRYPTO_PRIVATE_KEY, apiDecryptProperties.getPrivateKey()); + param.put(CryptoFilter.CRYPTO_HEADER_FLAG, apiDecryptProperties.getHeaderFlag()); + registration.setInitParameters(param); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + return registration; + } +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/AesEncryptor.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/AesEncryptor.java new file mode 100644 index 00000000..29b4f4b4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/AesEncryptor.java @@ -0,0 +1,57 @@ +package org.dromara.cryptapi.core; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import org.dromara.cryptapi.enums.EncodeType; + +import java.nio.charset.StandardCharsets; + +/** + * AES算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class AesEncryptor { + + private final AES aes; + + public AesEncryptor(EncryptContext context) { + String password = context.getPassword(); + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES没有获得秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度应该为16位、24位、32位,实际为" + password.length() + "位"); + } + aes = SecureUtil.aes(context.getPassword().getBytes(StandardCharsets.UTF_8)); + } + + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return aes.encryptHex(value); + } else { + return aes.encryptBase64(value); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + public String decrypt(String value) { + return this.aes.decryptStr(value); + } +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/EncryptContext.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/EncryptContext.java new file mode 100644 index 00000000..76804adb --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/EncryptContext.java @@ -0,0 +1,35 @@ +package org.dromara.cryptapi.core; + +import lombok.Data; +import org.dromara.cryptapi.enums.EncodeType; + +/** + * 加密上下文 用于encryptor传递必要的参数。 + * + * @author 老马 + * @version 4.6.0 + */ +@Data +public class EncryptContext { + + /** + * 安全秘钥 + */ + private String password; + + /** + * 公钥 + */ + private String publicKey; + + /** + * 私钥 + */ + private String privateKey; + + /** + * 编码方式,base64/hex + */ + private EncodeType encode; + +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/RsaEncryptor.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/RsaEncryptor.java new file mode 100644 index 00000000..9f8806d1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/RsaEncryptor.java @@ -0,0 +1,52 @@ +package org.dromara.cryptapi.core; + +import cn.hutool.core.codec.Base64; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.cryptapi.enums.EncodeType; + + +/** + * RSA算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class RsaEncryptor { + + private final RSA rsa; + + public RsaEncryptor(EncryptContext context) { + String privateKey = context.getPrivateKey(); + String publicKey = context.getPublicKey(); + if (StringUtils.isAnyEmpty(privateKey, publicKey)) { + throw new IllegalArgumentException("RSA公私钥均需要提供,公钥加密,私钥解密。"); + } + this.rsa = SecureUtil.rsa(Base64.decode(privateKey), Base64.decode(publicKey)); + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return rsa.encryptHex(value, KeyType.PublicKey); + } else { + return rsa.encryptBase64(value, KeyType.PublicKey); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + public String decrypt(String value) { + return this.rsa.decryptStr(value, KeyType.PrivateKey); + } +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/enums/EncodeType.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/enums/EncodeType.java new file mode 100644 index 00000000..7ee356af --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/enums/EncodeType.java @@ -0,0 +1,13 @@ +package org.dromara.cryptapi.enums; + +public enum EncodeType { + /** + * base64编码 + */ + BASE64, + + /** + * 16进制编码 + */ + HEX +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/CryptoFilter.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/CryptoFilter.java new file mode 100644 index 00000000..b96e74db --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/CryptoFilter.java @@ -0,0 +1,54 @@ +package org.dromara.cryptapi.filter; + +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import lombok.SneakyThrows; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.cryptapi.core.EncryptContext; +import org.dromara.cryptapi.core.RsaEncryptor; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; + +import java.util.Objects; + + +/** + * Crypto 过滤器 + * + * @author wdhcr + */ +public class CryptoFilter implements Filter { + + public static final String CRYPTO_PUBLIC_KEY = "publicKey"; + public static final String CRYPTO_PRIVATE_KEY = "privateKey"; + public static final String CRYPTO_HEADER_FLAG = "headerFlag"; + private RsaEncryptor rsaEncryptor; + private String headerFlag; + + + @Override + public void init(FilterConfig filterConfig) { + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setPublicKey(filterConfig.getInitParameter(CryptoFilter.CRYPTO_PUBLIC_KEY)); + encryptContext.setPrivateKey(filterConfig.getInitParameter(CryptoFilter.CRYPTO_PRIVATE_KEY)); + headerFlag = filterConfig.getInitParameter(CryptoFilter.CRYPTO_HEADER_FLAG); + rsaEncryptor = new RsaEncryptor(encryptContext); + } + + @SneakyThrows + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { + ServletRequest requestWrapper = null; + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + if (StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE) + && (HttpMethod.PUT.matches(httpServletRequest.getMethod()) || HttpMethod.POST.matches(httpServletRequest.getMethod()))) { + requestWrapper = new DecryptRequestBodyWrapper(httpServletRequest, rsaEncryptor, headerFlag); + } + chain.doFilter(Objects.requireNonNullElse(requestWrapper, request), response); + } + + @Override + public void destroy() { + + } +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/DecryptRequestBodyWrapper.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/DecryptRequestBodyWrapper.java new file mode 100644 index 00000000..8d014c8d --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/DecryptRequestBodyWrapper.java @@ -0,0 +1,103 @@ +package org.dromara.cryptapi.filter; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.io.IoUtil; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.exception.base.BaseException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.cryptapi.core.AesEncryptor; +import org.dromara.cryptapi.core.EncryptContext; +import org.dromara.cryptapi.core.RsaEncryptor; +import org.dromara.cryptapi.enums.EncodeType; +import org.springframework.http.MediaType; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +/** + * 解密请求参数工具类 + * + * @author wdhcr + */ +public class DecryptRequestBodyWrapper extends HttpServletRequestWrapper { + + private final byte[] body; + + public DecryptRequestBodyWrapper(HttpServletRequest request, RsaEncryptor rsaEncryptor, String headerFlag) throws IOException { + super(request); + String requestRsa = request.getHeader(headerFlag); + if (StringUtils.isEmpty(requestRsa)) { + throw new BaseException("加密AES的动态密码不能为空"); + } + String decryptAes = new String(Base64.decode(rsaEncryptor.decrypt(requestRsa))); + request.setCharacterEncoding(Constants.UTF8); + byte[] readBytes = IoUtil.readBytes(request.getInputStream(), false); + String requestBody = StringUtils.toEncodedString(readBytes, StandardCharsets.UTF_8); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setPassword(decryptAes); + encryptContext.setEncode(EncodeType.BASE64); + AesEncryptor aesEncryptor = new AesEncryptor(encryptContext); + String decryptBody = aesEncryptor.decrypt(requestBody); + body = decryptBody.getBytes(StandardCharsets.UTF_8); + } + + @Override + public BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + + @Override + public int getContentLength() { + return body.length; + } + + @Override + public long getContentLengthLong() { + return body.length; + } + + @Override + public String getContentType() { + return MediaType.APPLICATION_JSON_VALUE; + } + + + @Override + public ServletInputStream getInputStream() { + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + return new ServletInputStream() { + @Override + public int read() { + return bais.read(); + } + + @Override + public int available() { + return body.length; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + }; + } +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/handler/DecryptUrlHandler.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/handler/DecryptUrlHandler.java new file mode 100644 index 00000000..cf01ea79 --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/handler/DecryptUrlHandler.java @@ -0,0 +1,55 @@ +package org.dromara.cryptapi.handler; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ReUtil; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.dromara.cryptapi.annotation.ApiDecrypt; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import java.util.*; +import java.util.regex.Pattern; + +/** + * 获取需要解密的Url配置 + * + * @author wdhcr + */ +@Data +@Component +@RequiredArgsConstructor +public class DecryptUrlHandler implements InitializingBean { + + private static final Pattern PATTERN = Pattern.compile("\\{(.*?)}"); + + private List urls = new ArrayList<>(); + + private final RequestMappingHandlerMapping requestMappingHandlerMapping; + + @Override + public void afterPropertiesSet() { + Set set = new HashSet<>(); + Map map = requestMappingHandlerMapping.getHandlerMethods(); + List requestMappingInfos = map.entrySet().stream().filter(item -> { + HandlerMethod method = item.getValue(); + ApiDecrypt decrypt = method.getMethodAnnotation(ApiDecrypt.class); + // 标有解密注解的并且是post 或者put 请求的handler + return decrypt != null && CollectionUtil.containsAny(item.getKey().getMethodsCondition().getMethods(), Arrays.asList(RequestMethod.PUT, RequestMethod.POST)); + }).map(Map.Entry::getKey).toList(); + requestMappingInfos.forEach(info -> { + // 获取注解上边的 path 替代 path variable 为 * + Optional.ofNullable(info.getPathPatternsCondition()) + .map(PathPatternsRequestCondition::getPatterns) + .orElseGet(HashSet::new) + .forEach(url -> set.add(ReUtil.replaceAll(url.getPatternString(), PATTERN, "*"))); + }); + urls.addAll(set); + } + +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/properties/ApiDecryptProperties.java b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/properties/ApiDecryptProperties.java new file mode 100644 index 00000000..f7dc6b0b --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/properties/ApiDecryptProperties.java @@ -0,0 +1,34 @@ +package org.dromara.cryptapi.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * api解密属性配置类 + * @author wdhcr + */ +@Data +@ConfigurationProperties(prefix = "api-decrypt") +public class ApiDecryptProperties { + + /** + * 加密开关 + */ + private Boolean enable; + + /** + * 头部标识 + */ + private String headerFlag; + + + /** + * 公钥 + */ + private String publicKey; + + /** + * 私钥 + */ + private String privateKey; +} diff --git a/ruoyi-common/ruoyi-common-cryptapi/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-cryptapi/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..533d4be7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-cryptapi/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.cryptapi.config.ApiDecryptConfig