配合前端使用jsencrypt实现接口参数加密功能, 可在application.yml中全局开启, 也可通过自定义注解@ApiDecrypt对单独接口开启.
This commit is contained in:
parent
ee8922729e
commit
10b5b0e82a
@ -87,6 +87,12 @@
|
|||||||
<artifactId>JustAuth</artifactId>
|
<artifactId>JustAuth</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 接口请求参数加密模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-cryptapi</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- skywalking 整合 logback -->
|
<!-- skywalking 整合 logback -->
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
|
@ -173,6 +173,16 @@ mybatis-encryptor:
|
|||||||
publicKey:
|
publicKey:
|
||||||
privateKey:
|
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:
|
springdoc:
|
||||||
api-docs:
|
api-docs:
|
||||||
# 是否开启接口文档
|
# 是否开启接口文档
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
<module>ruoyi-common-encrypt</module>
|
<module>ruoyi-common-encrypt</module>
|
||||||
<module>ruoyi-common-tenant</module>
|
<module>ruoyi-common-tenant</module>
|
||||||
<module>ruoyi-common-websocket</module>
|
<module>ruoyi-common-websocket</module>
|
||||||
|
<module>ruoyi-common-cryptapi</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<artifactId>ruoyi-common</artifactId>
|
<artifactId>ruoyi-common</artifactId>
|
||||||
|
@ -171,6 +171,13 @@
|
|||||||
<artifactId>ruoyi-common-websocket</artifactId>
|
<artifactId>ruoyi-common-websocket</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 接口请求参数加密模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-cryptapi</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
34
ruoyi-common/ruoyi-common-cryptapi/pom.xml
Normal file
34
ruoyi-common/ruoyi-common-cryptapi/pom.xml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<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">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>ruoyi-common-cryptapi</artifactId>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
ruoyi-common-cryptapi 接口请求参数加密模块
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-crypto</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -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 {
|
||||||
|
}
|
@ -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<CryptoFilter> cryptoFilterRegistration() {
|
||||||
|
FilterRegistrationBean<CryptoFilter> registration = new FilterRegistrationBean<>();
|
||||||
|
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
||||||
|
registration.setFilter(new CryptoFilter());
|
||||||
|
List<String> 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<String, String> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package org.dromara.cryptapi.enums;
|
||||||
|
|
||||||
|
public enum EncodeType {
|
||||||
|
/**
|
||||||
|
* base64编码
|
||||||
|
*/
|
||||||
|
BASE64,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16进制编码
|
||||||
|
*/
|
||||||
|
HEX
|
||||||
|
}
|
@ -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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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<String> urls = new ArrayList<>();
|
||||||
|
|
||||||
|
private final RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
|
||||||
|
List<RequestMappingInfo> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
org.dromara.cryptapi.config.ApiDecryptConfig
|
Loading…
x
Reference in New Issue
Block a user