配合前端使用jsencrypt实现接口参数加密功能, 可在application.yml中全局开启, 也可通过自定义注解@ApiDecrypt对单独接口开启.
已添加12个文件
已修改4个文件
524 ■■■■■ 文件已修改
ruoyi-admin/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/pom.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-bom/pom.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/pom.xml 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/annotation/ApiDecrypt.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/config/ApiDecryptConfig.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/AesEncryptor.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/EncryptContext.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/core/RsaEncryptor.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/enums/EncodeType.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/CryptoFilter.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/filter/DecryptRequestBodyWrapper.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/handler/DecryptUrlHandler.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/java/org/dromara/cryptapi/properties/ApiDecryptProperties.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-cryptapi/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/pom.xml
@@ -87,6 +87,12 @@
            <artifactId>JustAuth</artifactId>
        </dependency>
        <!-- æŽ¥å£è¯·æ±‚参数加密模块 -->
        <dependency>
            <groupId>org.dromara</groupId>
            <artifactId>ruoyi-common-cryptapi</artifactId>
        </dependency>
        <!-- skywalking æ•´åˆ logback -->
<!--        <dependency>-->
ruoyi-admin/src/main/resources/application.yml
@@ -173,6 +173,16 @@
  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:
    # æ˜¯å¦å¼€å¯æŽ¥å£æ–‡æ¡£
ruoyi-common/pom.xml
@@ -33,6 +33,7 @@
        <module>ruoyi-common-encrypt</module>
        <module>ruoyi-common-tenant</module>
        <module>ruoyi-common-websocket</module>
        <module>ruoyi-common-cryptapi</module>
    </modules>
    <artifactId>ruoyi-common</artifactId>
ruoyi-common/ruoyi-common-bom/pom.xml
@@ -171,6 +171,13 @@
                <artifactId>ruoyi-common-websocket</artifactId>
                <version>${revision}</version>
            </dependency>
            <!-- æŽ¥å£è¯·æ±‚参数加密模块 -->
            <dependency>
                <groupId>org.dromara</groupId>
                <artifactId>ruoyi-common-cryptapi</artifactId>
                <version>${revision}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
ruoyi-common/ruoyi-common-cryptapi/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -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>
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 {
}
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<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;
    }
}
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);
    }
}
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;
}
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);
    }
}
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
}
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() {
    }
}
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) {
            }
        };
    }
}
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<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);
    }
}
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;
}
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