# sgchen-security **Repository Path**: chenshaogui/sgchen-security ## Basic Information - **Project Name**: sgchen-security - **Description**: spring 接口请求加解密处理、数据库加密存储处理、接口敏感数据脱敏处理 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 4 - **Created**: 2025-06-10 - **Last Updated**: 2025-09-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: 数据加密, 数据脱敏 ## README # 数据传输加解密及数据存储加解密 基于SpringBoot和Mybatis的数据安全处理,在数据持久层对数据进行加/解密,接口请求加密解密,接口的脱敏处理。 1、通过注解在保存数据的时候将指定字段进行加密处理,查询时自动解密\ 2、通过注解在查询数据的时候对指定字段进行脱敏处理\ 3、通过实现接口请求和相应数据的解密加密以及敏感数据的脱敏处理 *** 前端秘钥存储可以使用用户密码加密,后端秘钥配置可以用-Djasypt.encryptor.password= 加密存储 *** SpringBoot+MyBatis-Plus ,HuTool的工具包、Lombok插件以及Bouncy Castle加密包、fastjson2工具 https://gitee.com/chenshaogui/sgchen-security 数据传输加解密及数据存储加解密使用手册 # 一、概要介绍 数据传输各模式对比 | 加密类型 | 模式 | 核心特点 | 优点 | 缺点 | 典型用途 | |-------|-----------|-------------------|---------------|------------------|-------------------| | 对称加密 | ECB(无 IV) | 块独立加密,无 IV | 简单、效率高 | 密文块重复,安全性极差 | 已弃用,仅早期低安全场景 | | 对称加密 | 固定 IV | 用固定 IV 混合加密 | 实现简单,比 ECB 安全 | 明文开头重复时密文重复,安全性弱 | 内部低敏感、短周期传输 | | 对称加密 | 动态 IV | 随机 IV,随密文传输 | 安全性高,无密文重复 | 需传输 IV,依赖 IV 随机性 | HTTPS、敏感 API、文件加密 | | 非对称混合 | 请求头密钥模式 | 单次请求独立生成对称密钥,公钥加密 | 安全高效,适合单次请求 | 每次请求有非对称加密开销 | 开放平台 API、一次性数据提交 | | 非对称混合 | 会话模式 | 会话初期协商会话密钥,后续对称加密 | 效率极高,适合持续通信 | 会话密钥泄露影响整个会话 | 即时通讯、VPN、在线会议 | ## 非对称秘钥算法介绍 | **算法** | **密钥长度范围** | **推荐密钥长度** | **安全强度(位)** | |------------|---------------------|---------------|---------------| | RSA | 1024-4096 位 | 2048 位 | 约 112 位 | | DSA | 1024-3072 位 | 2048 位 | 约 112 位 | | ElGamal | 1024-4096 位 | 2048 位 | 约 112 位 | | ECDSA/ECDH | P-256, P-384, P-521 | P-256 (128 位) | 128/192/256 位 | | SM2 | SM2-P-256 | 256 位 | 128 位 | # 二、SpringBoot项目公共配置 ## 依赖包引入 ```xml org.springframework.boot spring-boot-starter-web 2.7+ com.baomidou mybatis-plus-boot-starter 3.5+ cn.hutool hutool-all 5.8+ org.springframework.boot spring-boot-starter-data-redis 2.7+ ``` ## 引入加解密工具Maven包 ```xml io.gitee.chenshaogui sgchen-security 1.0.42 ``` ## springBoot启动类加注解 ```java @SpringBootApplication @EnableDataSecurity public class DataSecurityApplication { public static void main(String[] args) { SpringApplication.run(DataSecurityApplication.class, args); } } ``` # 三、*数据存储* ## *项目集成秘钥参数配置* ```java @Configuration public class DataSecurityConfig { @Bean public SecretConfig secretConfig() { return SecretConfig.builder() .dbSecretKey("加密秘钥") // 数据存储加密算法 .dbAlgorithm(SecretAlgorithm.PKCS7) .build(); } } ``` ## *开发使用方法* ### 实体类(VO、DTO、PO等)配置 ```markdown @EncryptEntity 实体类上注解 @EncryptField 实体类上需要新增 查询 加解密字段注解 ``` 实体类可以加@DesensitizedField脱敏字段查出的结果脱敏,但不建议这样做。会影响后面的结果业务处理 ### 实体类代码样例参考 ```java @Data @TableName("account") @EncryptEntity public class AccountPo { /** * id */ @TableId(value = "id", type= IdType.AUTO) private Integer id; /** * 账号 */ @EncryptField private String account; /** * 密码 */ @EncryptField private String password; /** * email */ private String email; } ``` ### Mybatis Mapper文件查询方式 ```java // 使用Mapper.xml查询时单个参数注解 @EncryptParam List getInfoByAccount(@EncryptParam("account") @Param("account") String account); // 当参数是对象时只需要在类上加注解 List listByFilter(@Param("entity") AccountPo accountPo); ``` ### Mybatis Wrapper内置Api调用使用 ```java public List getInfoByAccount(AccountPo accountPo) { EncryptLambdaQueryWrapper queryWrapper = new EncryptLambdaQueryWrapper<>(); queryWrapper.eq(AccountPo::getAccount, accountPo.getAccount()); return accountMapper.selectList(queryWrapper); } ``` 查询时使用 EncryptLambdaQueryWrapper 更新时调用 EncryptLambdaUpdateWrapper ### Mapper层代码样例参考 ```java @Service public class AccountServiceImpl implements AccountService { @Resource private AccountMapper accountMapper; @Override public void addAccount(AccountPo accountPo) { accountMapper.insert(accountPo); } @Override public List queryAllWrapper() { return accountMapper.selectList(Wrappers.emptyWrapper()); } @Override public void updatePasswordByAccount(String account, String password) { accountMapper.updatePasswordByAccount(account, password); } @Override public void updateByIdWrapper(AccountPo accountPo) { accountMapper.updateById(accountPo); } @Override public List getInfoByMapperParams(AccountPo accountPo) { return accountMapper.getInfoByAccount(accountPo.getAccount()); } @Override public List getInfoByWrapper(AccountPo accountPo) { EncryptLambdaQueryWrapper queryWrapper = new EncryptLambdaQueryWrapper<>(); queryWrapper.eq(AccountPo::getAccount, accountPo.getAccount()); return accountMapper.selectList(queryWrapper); } @Override public List listByMapperEntity(AccountPo accountPo) { return accountMapper.listByFilter(accountPo); } @Override public AccountPo infoByWrapperId(Integer id) { return accountMapper.selectById(id); } @Override public void updateByIdUpdateWrapper(AccountPo accountPo) { EncryptLambdaUpdateWrapper queryWrapper = new EncryptLambdaUpdateWrapper<>(); queryWrapper.eq(AccountPo::getId, accountPo.getId()); queryWrapper.set(AccountPo::getEmail,accountPo.getEmail()); queryWrapper.set(AccountPo::getAccount,accountPo.getAccount()); accountMapper.update(null,queryWrapper); } @Override public void updateUpdateWrapper(AccountPo accountPo) { EncryptLambdaQueryWrapper queryWrapper = new EncryptLambdaQueryWrapper<>(); queryWrapper.eq(AccountPo::getId, accountPo.getId()); accountMapper.update(accountPo,queryWrapper); } } ``` # 四、数据传输 ## *开发使用方法(包含数据脱敏)* ### Controller层类注解:类注解方式(方法和类注解方式二选一) ```java @EncryptController({ @DesensitizedUnit(field = "secondPhone", mode = DesensitizedMode.mobile), @DesensitizedUnit(field = "secondReceiver", mode = DesensitizedMode.name), @DesensitizedUnit(field = "auditor", mode = DesensitizedMode.name), @DesensitizedUnit(field = "secondAddress", mode = DesensitizedMode.address), @DesensitizedUnit(field = "userAccount", mode = DesensitizedMode.mobile) }) public class AccountController {} ``` ### Controller层方法注解:方法上的加密请求注解(方法和类注解方式二选一) ```java @EncryptRequest({ @DesensitizedUnit(field = "secondPhone", mode = DesensitizedMode.mobile), @DesensitizedUnit(field = "secondReceiver", mode = DesensitizedMode.name), @DesensitizedUnit(field = "auditor", mode = DesensitizedMode.name), @DesensitizedUnit(field = "secondAddress", mode = DesensitizedMode.address), @DesensitizedUnit(field = "userAccount", mode = DesensitizedMode.mobile) }) public AjaxResult queryAllWrapper() {} ``` ## *项目集成秘钥参数配置* ### 对称和非对称自定义加密 使用其他对称加密算法 ```html PKCS5("AES/ECB/PKCS5Padding", true, 128, 16), PKCS7("AES/ECB/PKCS7Padding", true, 128, 16), CBC_PKCS7("AES/CBC/PKCS7Padding", true, 128, 16), SM4_ECB_PKCS7("SM4/ECB/PKCS7Padding", true, 128, 16), SM4_CBC_PKCS7("SM4/CBC/PKCS7Padding", true, 128, 16), /** * 以下是严格模式,当加解密失败时抛出异常 */ PKCS5_STRICT("AES/ECB/PKCS5Padding", false, 128, 16), PKCS7_STRICT("AES/ECB/PKCS7Padding", false, 128, 16), CBC_PKCS7_STRICT("AES/CBC/PKCS7Padding", false, 128, 16), SM4_ECB_PKCS7_STRICT("SM4/ECB/PKCS7Padding", false, 128, 16), SM4_CBC_PKCS7_STRICT("SM4/CBC/PKCS7Padding", false, 128, 16), /** * 自定义算法占位符 */ CUSTOM_ALGORITHM(null, null, 128, 16); public static synchronized void configureCustomAlgorithm(String algorithm, Boolean isSkipError, Integer keySize, Integer ivSize){} ``` 使用其他的非对称秘钥算法 ```html /** * RSA 非对称加密混合,秘钥会话模式 */ RSA_WITH_SESSION("RSA", "RSA,秘钥会话模式", RequestKeyTransMode.SESSION, 2048), /** * 非对称加密混合,请求头秘钥模式 */ RSA_WITH_HEADER("RSA", "RSA,请求头秘钥模式", RequestKeyTransMode.HEADER, 2048), /** * ECC 非对称加密混合,秘钥会话模式 */ ECDH_WITH_SESSION("ECDH", "ECDH,秘钥会话模式", RequestKeyTransMode.SESSION, 256), /** * ECC 非对称加密模式 */ ECDH_WITH_HEADER("ECDH", "ECDH,请求头秘钥模式", RequestKeyTransMode.HEADER, 256), /** * ELGAMAL 非对称加密混合,秘钥会话模式 */ ELGAMAL_WITH_SESSION("ElGamal", "ELGAMAL,秘钥会话模式", RequestKeyTransMode.SESSION, 256), /** * ElGamal 非对称加密模式 */ ELGAMAL_WITH_HEADER("ElGamal", "ElGamal,请求头秘钥模式", RequestKeyTransMode.HEADER, 256), /** * SM2 非对称加密混合,秘钥会话模式 */ SM2_WITH_SESSION("EC", "SM2,秘钥会话模式", RequestKeyTransMode.SESSION, 256), /** * SM2 非对称加密模式 */ SM2_WITH_HEADER("EC", "SM2,请求头秘钥模式", RequestKeyTransMode.HEADER, 256), /** * 自定义算法占位符 */ CUSTOM_ALGORITHM(null, null, null, null); public static synchronized void configureCustomAlgorithm(String algorithm, String description, RequestKeyTransMode keyTransMode, Integer keySize) ``` 可以调用configureCustomAlgorithm方法配置自定义算法,key和iv的长度,自定义算法代码样例: ```java @Configuration public class DataSecurityConfig { @Bean public SecretConfig secretConfig() { // 配置对称秘钥的自定义算法 SecretAlgorithm.configureCustomAlgorithm("DES/CBC/PKCS5Padding", false, 56, 8); // 配置非对称秘钥的自定义算法 RequestAsymmetricMode.configureCustomAlgorithm("RSA", "RSA,1024大小的算法", RequestKeyTransMode.SESSION, 1024); return SecretConfig.builder() .reqAlgorithm(SecretAlgorithm.CUSTOM_ALGORITHM) .requestAsymmetricMode(RequestAsymmetricMode.CUSTOM_ALGORITHM) .dbSecretKey("数据存储加密秘钥") // 不使用可以不配置 // 数据存储加解密算法 .dbAlgorithm(SecretAlgorithm.PKCS7) // 不使用可以不配置 .build(); } } ``` ### Feign调用时使用方法 ```java @Configuration public class FeignRequestInterceptor implements RequestInterceptor { @Bean public feign.Logger.Level loggerLevel() { return feign.Logger.Level.FULL; } @Override public void apply(RequestTemplate requestTemplate) { requestTemplate.header(SecurityConstants.FEIGN_CLIENT_CALL, "true"); // to do something } } ``` ### 对称加密【ECB(无IV)模式】: AES、SM4、自定义对称加密 #### 加解密流程 1.请求使用固定秘钥加密的数据传输 客户端 → 发送【固定秘钥加密 的请求数据】→ 服务端 服务端 → 固定秘钥加密解密请求数据 → 处理业务 → 用客户端固定秘钥加密响应 → 返回客户端 #### 使用方法 * 1、项目秘钥配置【使用AES/ECB/PKCS7Padding秘钥为例】 ```java @Configuration public class DataSecurityConfig { @Bean public SecretConfig secretConfig() { return SecretConfig.builder() .reqSecretKey("请求存储加密秘钥") .reqAlgorithm(SecretAlgorithm.PKCS7) .dbSecretKey("数据存储加密秘钥") // 不使用可以不配置 // 数据存储加解密算法 .dbAlgorithm(SecretAlgorithm.PKCS7) // 不使用可以不配置 .build(); } } ``` * 2、请求数据传输用例(用ApiPost模拟) | 步骤 | 处理方法 | |:------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 参数加密 | const key = CryptoJS.enc.Utf8.parse("0123456789abcdeffedcba9876543210");
//加密方法
function Encrypt(word) {
    let srcs = CryptoJS.enc.Utf8.parse(typeof word === "string" ? word : JSON.stringify(word));
    let encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.toString();
}
let requests = Encrypt(request.request_bodys);
pm.request.body.raw = requests;
| | 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
RequestBody请求数据:
MCORifq5PMEjU8+q3F9A0nkJSH/iziLmuuL0HIpBk4M=
| | 返回数据解密 | const key = CryptoJS.enc.Utf8.parse("0123456789abcdeffedcba9876543210");
//解密方法
function Decrypt(word) {
    let decrypt = CryptoJS.AES.decrypt(word.replaceAll("\"", ""), key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
    let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
}
let responses = Decrypt(response.raw.responseText);
console.log(JSON.parse(responses))
pm.response.setBody(responses);
| ### 对称加密【固定IV】: AES、SM4、自定义对称加密 #### 加解密流程 1.请求使用固定秘钥和固定IV加密的数据传输 客户端 → 发送【固定秘钥和固定IV加密 的请求数据】→ 服务端 服务端 → 固定秘钥和固定IV加密解密请求数据 → 处理业务 → 用客户端固定秘钥和固定IV加密响应 → 返回客户端 #### 使用方法 * 1、项目秘钥配置【使用固定秘钥和固定IV加密为例】 ```java @Configuration public class DataSecurityConfig { @Bean public SecretConfig secretConfig() { return SecretConfig.builder() .reqSecretKey("0123456789abcdeffedcba9876543210") .reqAlgorithm(SecretAlgorithm.CBC_PKCS7) .reqSecretIV("0102030405060708") .dbSecretKey("testtest12345678") .dbAlgorithm(SecretAlgorithm.PKCS7) .build(); } } ``` * 2、请求数据传输用例(采用16进制的IV模式,16进制的key,base64的IV请参考:动态Base64编码IV,前端用ApiPost模拟) | 步骤 | 处理方法 | |:------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 参数加密 | let key = "0123456789abcdeffedcba9876543210";
const iv = CryptoJS.enc.Utf8.parse('0102030405060708');   //十六位十六进制数作为密钥偏移量
//加密方法
function Encrypt(word) {
    let srcs = CryptoJS.enc.Utf8.parse(typeof word === "string" ? word : JSON.stringify(word));
    key = CryptoJS.enc.Hex.parse(key);
    let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.toString();
}
let requests = Encrypt(request.request_bodys);
pm.request.body.raw = requests;
| | 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
RequestBody请求数据:
aHoFvEIrf7wDCT3jlsCiMizWg5KAu000+fI/HPW7IMY=
| | 返回数据解密 | let key = "0123456789abcdeffedcba9876543210";
const iv = CryptoJS.enc.Utf8.parse('0102030405060708');
//解密方法
function Decrypt(word) {
    key = CryptoJS.enc.Hex.parse(key);
    let decrypt = CryptoJS.AES.decrypt(word.replaceAll("\"", ""), key, { mode: CryptoJS.mode.CBC,iv:iv,padding: CryptoJS.pad.Pkcs7 });
    let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
}
let responses = Decrypt(response.raw.responseText);
console.log(JSON.parse(responses))
pm.response.setBody(responses);
| ### 对称加密【动态16进制IV】: AES、SM4、自定义对称加密 #### 加解密流程 1.请求使用固定秘钥和动态16进制IV加密的数据传输 客户端 → 发送【固定秘钥和动态16进制IV加密 的请求数据】→ 服务端 服务端 → 固定秘钥和动态16进制IV加密解密请求数据 → 处理业务 → 用客户端固定秘钥和动态16进制IV加密响应 → 返回客户端 #### 使用方法 * 1、项目秘钥配置【使用固定秘钥和动态16进制IV加密为例】 ```java @Configuration public class DataSecurityConfig { @Bean public SecretConfig secretConfig() { return SecretConfig.builder() .reqSecretKey("0123456789abcdeffedcba9876543210") .reqAlgorithm(SecretAlgorithm.SM4_PKCS7) .dbSecretKey("testtest12345678") .dbAlgorithm(SecretAlgorithm.PKCS7) .build(); } } ``` * 2、请求数据传输用例(采用16进制的IV模式,16进制的key,base64的IV请参考:动态Base64编码IV,前端用ApiPost模拟) | 步骤 | 处理方法 | |:------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 参数加密 | // 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba9876543210"; // 必须是16字节(128位)
// 生成 16 字节随机 IV(以 WordArray 格式表示)
const iv = CryptoJS.lib.WordArray.random(16);
// 转换为十六进制字符串(可读性更好)
const ivHex = iv.toString(CryptoJS.enc.Hex);
// 请求前脚本 - SM4加密请求数据并以Base64格式输出
function encryptData(word, key, iv) {
    // 使用SM4-CBC模式加密
    let encryptedHex = sm4.encrypt(word, key, { mode: 'cbc', iv: iv }) // 加密,cbc 模式
    // 将16进制字符串转换为字节数组
    var bytes = hexToBytes(encryptedHex);
    // 将字节数组转换为Base64
    var encryptedBase64 = bytesToBase64(bytes);
    return encryptedBase64;
}

// 辅助函数:16进制字符串转字节数组
function hexToBytes(hex) {
    var bytes = [];
    for (var i = 0; i < hex.length; i += 2) {
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }
    return bytes;
}
// 辅助函数:字节数组转Base64
function bytesToBase64(bytes) {
    var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    var result = '';
    var i = 0;

    while (i < bytes.length) {
        var byte1 = bytes[i++];
        var byte2 = i < bytes.length ? bytes[i++] : 0;
        var byte3 = i < bytes.length ? bytes[i++] : 0;

        var enc1 = byte1 >> 2;
        var enc2 = ((byte1 & 0x03) << 4) \| (byte2 >> 4);
        var enc3 = ((byte2 & 0x0F) << 2) \| (byte3 >> 6);
        var enc4 = byte3 & 0x3F;

        if (i > bytes.length + 1) {
            enc3 = enc4 = 64;
        } else if (i > bytes.length) {
            enc4 = 64;
        }

        result += base64Chars.charAt(enc1) + base64Chars.charAt(enc2) +
            base64Chars.charAt(enc3) + base64Chars.charAt(enc4);
    }

    return result;
}

// 获取请求数据
var requestData = pm.request.body.raw;
// 加密数据
var encryptedData = encryptData(requestData, secretKey, ivHex);
// 设置加密后的数据到请求体
pm.request.body.raw = encryptedData;
// 可选:添加加密信息头
pm.request.headers.upsert({
    key: 'X-Encrypted-IV',
    value: ivHex
});
| | 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
RequestBody请求数据:
4mDrMKIsb7soAEDD/d6QvmaHwIOB3cbkygUmJlp1KTgRT4qVYy5giiSFwtDD1KB+
| | 返回数据解密 | // 响应后脚本 - 解密SM4加密的响应数据
// 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba9876543210"; // 必须是16字节(128位)
function decryptData(ciphertext, key, iv) {
    // 使用SM4-CBC模式解密
    let decryptStr = ciphertext.replaceAll("\"", "");
    // 将Base64转换为字节数组
    var ciphertextBytes = base64ToBytes(decryptStr);
    // 将字节数组转换为16进制字符串
    var ciphertextHex = bytesToHex(ciphertextBytes);
    // key = CryptoJS.enc.Hex.parse(key);
    // 使用SM4-CBC模式加密
    var decryptedResult = sm4.decrypt(ciphertextHex, key, { mode: 'cbc', iv: iv })
    return decryptedResult;
}

// 辅助函数:Base64转字节数组
function base64ToBytes(base64) {
    var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    base64 = base64.replace(/=+$/, '');

    var bytes = [];
    for (var i = 0; i < base64.length; i += 4) {
        var enc1 = base64Chars.indexOf(base64.charAt(i));
        var enc2 = base64Chars.indexOf(base64.charAt(i + 1));
        var enc3 = base64Chars.indexOf(base64.charAt(i + 2));
        var enc4 = base64Chars.indexOf(base64.charAt(i + 3));

        var byte1 = (enc1 << 2) \| (enc2 >> 4);
        var byte2 = ((enc2 & 0x0F) << 4) \| (enc3 >> 2);
        var byte3 = ((enc3 & 0x03) << 6) \| enc4;

        bytes.push(byte1);
        if (enc3 !== 64) bytes.push(byte2);
        if (enc4 !== 64) bytes.push(byte3);
    }

    return bytes;
}
// 辅助函数:字节数组转16进制字符串
function bytesToHex(bytes) {
    var hex = [];
    for (var i = 0; i < bytes.length; i++) {
        var b = bytes[i];
        hex.push((b < 16 ? '0' : '') + b.toString(16));
    }
    return hex.join('');
}

// 获取响应数据
var responseData = pm.response.text();
const envIV = pm.response.headers.get('X-Encrypted-IV');
// 解密数据
var decryptedData = decryptData(responseData, secretKey, envIV);
// 尝试解析为JSON(如果是JSON格式)
try {
    var jsonData = JSON.parse(decryptedData);
    pm.response.json = function () { return jsonData; };
} catch (e) {
    // 如果不是JSON,保留原始解密文本
    pm.response.text = function () { return decryptedData; };
}

// 记录解密结果到控制台
console.log("解密响应:", decryptedData);
| ### 对称加密【动态Base64编码IV】: AES、SM4、自定义对称加密 #### 加解密流程 1.请求使用固定秘钥和动态base64编码IV加密的数据传输 客户端 → 发送【固定秘钥和动态base64编码IV加密 的请求数据】→ 服务端 服务端 → 固定秘钥和动态base64编码IV加密解密请求数据 → 处理业务 → 用客户端固定秘钥和动态base64编码IV加密响应 → 返回客户端 #### 使用方法 * 1、项目秘钥配置【使用固定秘钥和base64编码IV加密为例】 ```java @Configuration public class DataSecurityConfig { @Bean public SecretConfig secretConfig() { return SecretConfig.builder() .reqSecretKey("0123456789abcdeffedcba9876543210") .reqAlgorithm(SecretAlgorithm.CBC_PKCS7) .dbSecretKey("testtest12345678") .dbAlgorithm(SecretAlgorithm.PKCS7) .build(); } } ``` * 2、请求数据传输用例(采用动态Base64编码的IV模式,16进制的key,前端用ApiPost模拟) | 步骤 | 处理方法 | |:------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 参数加密 | // 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba9876543210"; // 必须是16字节(128位)
// 生成 16 字节随机 IV(以 WordArray 格式表示)
var iv = CryptoJS.lib.WordArray.random(16);
// 转换为 Base64 字符串(适合在 HTTP 请求头中传输)
var ivBase64 = iv.toString(CryptoJS.enc.Base64);
// 转换为十六进制字符串(可读性更好)
var ivHex = iv.toString(CryptoJS.enc.Hex);
// 请求前脚本 - SM4加密请求数据并以Base64格式输出
function encryptData(word, key, iv) {
    let srcs = CryptoJS.enc.Utf8.parse(typeof word === "string" ? word : JSON.stringify(word));
    let keyStr = CryptoJS.enc.Utf8.parse(key);
    keyStr = CryptoJS.enc.Hex.parse(key);
    let ivstr = CryptoJS.enc.Base64.parse(iv);
    let encrypted = CryptoJS.AES.encrypt(srcs, keyStr, { iv: ivstr, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    console.log("加密字符串", encrypted.toString())
    return encrypted.toString();
}

// 辅助函数:16进制字符串转字节数组
function hexToBytes(hex) {
    var bytes = [];
    for (var i = 0; i < hex.length; i += 2) {
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }
    return bytes;
}
// 辅助函数:字节数组转Base64
function bytesToBase64(bytes) {
    var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    var result = '';
    var i = 0;

    while (i < bytes.length) {
        var byte1 = bytes[i++];
        var byte2 = i < bytes.length ? bytes[i++] : 0;
        var byte3 = i < bytes.length ? bytes[i++] : 0;

        var enc1 = byte1 >> 2;
        var enc2 = ((byte1 & 0x03) << 4) \| (byte2 >> 4);
        var enc3 = ((byte2 & 0x0F) << 2) \| (byte3 >> 6);
        var enc4 = byte3 & 0x3F;

        if (i > bytes.length + 1) {
            enc3 = enc4 = 64;
        } else if (i > bytes.length) {
            enc4 = 64;
        }

        result += base64Chars.charAt(enc1) + base64Chars.charAt(enc2) +
            base64Chars.charAt(enc3) + base64Chars.charAt(enc4);
    }

    return result;
}
// 获取请求数据
var requestData = pm.request.body.raw;
var encryptedData = encryptData(requestData, secretKey, ivBase64);
// 设置加密后的数据到请求体
pm.request.body.raw = encryptedData;
// 可选:添加加密信息头
pm.request.headers.upsert({
    key: 'X-Encrypted-IV',
    value: ivBase64
});
| | 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
RequestBody请求数据:
CbWiLmLavpkTaEglW9pNdCocnhQDiI5Ewt+6evPNBtnjBTOKub3szj10FMPf0yEw
| | 返回数据解密 | // 响应后脚本 - 解密SM4加密的响应数据
// 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba9876543210"; // 必须是16字节(128位)
function decryptData(ciphertext, key, iv) {
    let decryptStr = ciphertext.replaceAll("\"", "");
    let keyStr = CryptoJS.enc.Utf8.parse(key);
    keyStr = CryptoJS.enc.Hex.parse(key);
    let ivstr = CryptoJS.enc.Base64.parse(iv);
    var decryptedResult = CryptoJS.AES.decrypt(decryptStr, keyStr, { iv: ivstr, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    let decryptedStr = CryptoJS.enc.Utf8.stringify(decryptedResult);
    return decryptedStr.toString();
}

// 获取响应数据
var responseData = pm.response.text();
const envIV = pm.response.headers.get('X-Encrypted-IV');
// 解密数据
var decryptedData = decryptData(responseData, secretKey, envIV);
// 尝试解析为JSON(如果是JSON格式)
try {
    var jsonData = JSON.parse(decryptedData);
    pm.response.json = function () { return jsonData; };
} catch (e) {
    // 如果不是JSON,保留原始解密文本
    pm.response.text = function () { return decryptedData; };
}

// 记录解密结果到控制台
console.log("解密响应:", decryptedData);
| ### 非对称加密混合请求头秘钥模式【秘钥对称加密、传输数据非对称加密】: RSA、SM2、ECC(ECDH、ECDSA)、ElGamal、自定义非对称加密 #### 加解密流程(需要Redis支持) 1. 首次创建会话时传输对称密钥 客户端 → 生成对称密钥 2.请求携带客户端秘钥以及客户端秘钥加密的数据 客户端 → 发送【客户端秘钥加密的数据 + 非对称加密客户端秘钥 的请求数据】→ 服务端 服务端 → 用公钥解密客户端密钥 → 使用客户端秘钥解密请求数据 → 处理业务 → 用客户端秘钥加密响应 → 返回客户端 #### 默认参数配置(非对称密钥对有效期) ```yaml # 混合加密模式 csg-tsc: rsa-key: # RSA密钥有效期(小时),默认24小时 expiryHours: 24 ``` 当没有配置数据时将使用默认配置 #### 使用方法(多项目共用一个Redis,客户端编码必须配置) * 1、项目秘钥配置【使用SM4加密传输数据,SM2传输秘钥为例】 ```java @Configuration public class DataSecurityConfig { @Bean public SecretConfig secretConfig() { return SecretConfig.builder() .reqAlgorithm(SecretAlgorithm.SM4_CBC_PKCS7) .requestAsymmetricMode(RequestAsymmetricMode.SM2_WITH_HEADER) .dbSecretKey("数据存储加密秘钥") // 不使用可以不配置 // 数据存储加解密算法 .dbAlgorithm(SecretAlgorithm.PKCS7) // 不使用可以不配置 .clientCode("system") // 客户端编码 .build(); } } ``` * 2、前端获取公钥 ```html Get: localhost:9898/data-security/api/asymmetricTSC/public-key Response响应数据: { "publicKey": "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEFgFkoXDTKyP2jhigRUlrI3qO0LxZ3emioBNS8ReMYW19PMSEw+90mWmWBDcF8h0eUwDmpMWaXApfX2vRWWfwtw==", "version": "c72255c86c5f4993b39dea9458140fd7" } ``` * 3、前端使用公钥加密私钥 --自定义方法处理 * 4、请求数据传输用例(采用16进制的IV模式,base64的IV请参考:动态Base64编码IV,前端用ApiPost模拟) | 步骤 | 处理方法 | |:------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 参数加密 | // 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba7896543210"; // 必须是16字节(128位)
// 生成 16 字节随机 IV(以 WordArray 格式表示)
var iv = CryptoJS.lib.WordArray.random(16);
// 转换为 Base64 字符串(适合在 HTTP 请求头中传输)
// 转换为十六进制字符串(可读性更好)
var ivHex = iv.toString(CryptoJS.enc.Hex);
// 请求前脚本 - SM4加密请求数据并以Base64格式输出
function encryptData(word, key, iv) {
    // 如果数据是对象,转换为JSON字符串
    // 使用SM4-CBC模式加密
    let encryptedHex = sm4.encrypt(word, key, { mode: 'cbc', iv: iv }) // 加密,cbc 模式
    // 将16进制字符串转换为字节数组
    var bytes = hexToBytes(encryptedHex);
    // 将字节数组转换为Base64
    var encryptedBase64 = bytesToBase64(bytes);
    return encryptedBase64;
}

// 辅助函数:16进制字符串转字节数组
function hexToBytes(hex) {
    var bytes = [];
    for (var i = 0; i < hex.length; i += 2) {
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }
    return bytes;
}
// 辅助函数:字节数组转Base64
function bytesToBase64(bytes) {
    var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    var result = '';
    var i = 0;

    while (i < bytes.length) {
        var byte1 = bytes[i++];
        var byte2 = i < bytes.length ? bytes[i++] : 0;
        var byte3 = i < bytes.length ? bytes[i++] : 0;

        var enc1 = byte1 >> 2;
        var enc2 = ((byte1 & 0x03) << 4) \| (byte2 >> 4);
        var enc3 = ((byte2 & 0x0F) << 2) \| (byte3 >> 6);
        var enc4 = byte3 & 0x3F;

        if (i > bytes.length + 1) {
            enc3 = enc4 = 64;
        } else if (i > bytes.length) {
            enc4 = 64;
        }

        result += base64Chars.charAt(enc1) + base64Chars.charAt(enc2) +
            base64Chars.charAt(enc3) + base64Chars.charAt(enc4);
    }

    return result;
}
// 获取请求数据
var requestData = pm.request.body.raw;
var encryptedData = encryptData(requestData, secretKey, ivHex);
// 设置加密后的数据到请求体
pm.request.body.raw = encryptedData;
// 可选:添加加密信息头
pm.request.headers.upsert({
    key: 'X-Encrypted-IV',
    value: ivHex
});
| | 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
Header: X-Encrypted-ClientKey: BOv9lA7TLM358HTgsMa/0c3iPu8k+UShdw0H1iwMqqFBf+V/s7pplR7jT2cdUBYfRhj8fbeOI/dgy2/VVqG8e5qA/fDAVwKQmI0u0MuqNGoHg48UGhCbKwxzwk24cSZj0eZkO58B7v10kB1+sARE7hsSFbn+r8OAuSOwhSeoxGG8
RequestBody请求数据:
lelKWOI+fJO/6XrTnjqZqWeppGuC6zn+hK40W5pYKuv0ma/O3EFx7VXxI+geBdjV
ResponseBody: "tHgZ5ENlVhWq6QGmaaNRJy/DjU+1datQ2EiteFD9fAltwRR8EwX3gzROm1HwCa4hq8GOS+JMa64kcgrYzZ1WPRvqCw+Y6jEeOcgiNAxCAchN23Mv/dob0aeM4CwI5pzx1QGBsGJeTLle5Dv9oDkTyg=="
| | 返回数据解密 | // 响应后脚本 - 解密SM4加密的响应数据
// 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba7896543210"; // 必须是16字节(128位)
function decryptData(ciphertext, key, iv) {
    // 使用SM4-CBC模式解密
    let decryptStr = ciphertext.replaceAll("\"", "");
    // 将Base64转换为字节数组
    var ciphertextBytes = base64ToBytes(decryptStr);
    // 将字节数组转换为16进制字符串
    var ciphertextHex = bytesToHex(ciphertextBytes);
    // 使用SM4-CBC模式加密
    var decryptedResult = sm4.decrypt(ciphertextHex, key, { mode: 'cbc', iv: iv })
    return decryptedResult;
}
// 辅助函数:Base64转字节数组
function base64ToBytes(base64) {
    var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    base64 = base64.replace(/=+$/, '');
    var bytes = [];
    for (var i = 0; i < base64.length; i += 4) {
        var enc1 = base64Chars.indexOf(base64.charAt(i));
        var enc2 = base64Chars.indexOf(base64.charAt(i + 1));
        var enc3 = base64Chars.indexOf(base64.charAt(i + 2));
        var enc4 = base64Chars.indexOf(base64.charAt(i + 3));

        var byte1 = (enc1 << 2) \| (enc2 >> 4);
        var byte2 = ((enc2 & 0x0F) << 4) \| (enc3 >> 2);
        var byte3 = ((enc3 & 0x03) << 6) \| enc4;

        bytes.push(byte1);
        if (enc3 !== 64) bytes.push(byte2);
        if (enc4 !== 64) bytes.push(byte3);
    }

    return bytes;
}
// 辅助函数:字节数组转16进制字符串
function bytesToHex(bytes) {
    var hex = [];
    for (var i = 0; i < bytes.length; i++) {
        var b = bytes[i];
        hex.push((b < 16 ? '0' : '') + b.toString(16));
    }
    return hex.join('');
}

// 获取响应数据
var responseData = pm.response.text();
const envIV = pm.response.headers.get('X-Encrypted-IV');
// 解密数据
var decryptedData = decryptData(responseData, secretKey, envIV);
// 尝试解析为JSON(如果是JSON格式)
try {
    var jsonData = JSON.parse(decryptedData);
    pm.response.json = function () { return jsonData; };
} catch (e) {
    // 如果不是JSON,保留原始解密文本
    pm.response.text = function () { return decryptedData; };
}

// 记录解密结果到控制台
console.log("解密响应:", decryptedData);
| ### 非对称加密混合会话模式【秘钥对称加密、传输数据非对称加密】: RSA、SM2、ECC(ECDH、ECDSA)、ElGamal、自定义非对称加密 #### 加解密流程(需要Redis支持) 1. 首次创建会话时传输对称密钥 客户端 → 生成对称密钥 → 用服务端公钥加密 → 发送【加密的对称密钥】→ 服务端 服务端 → 用私钥解密对称密钥 → 生成会话ID → 存储【会话ID → 对称密钥】到Redis → 返回会话ID给客户端 2. 后续请求仅携带会话ID 客户端 → 发送【会话ID + 用客户端秘钥加密的请求数据】→ 服务端 服务端 → 用会话ID从Redis获取客户端密钥 → 解密请求数据 → 处理业务 → 用客户端秘钥加密响应 → 返回客户端 #### 默认参数配置(非对称密钥对、会话有效期,会话数和限流配置) ```yaml # 混合加密模式 csg-tsc: rsa-key: # 密钥有效期(小时),默认24小时 expiryHours: 24 rsa-session: # 最大会话数,默认100000 maxCount: 100000 # 会话过期时间,单位秒,默认8小时过期 expirySeconds: 28800 # 每个IP每分钟最多允许1000次请求,默认1000 ipRateLimit: 1000 # 如果设置为 60 秒,表示统计最近 60 秒内的请求次数. 默认60 ipRateWindow: 60 ``` 当没有配置数据时将使用默认配置 #### 使用方法(多项目共用一个Redis,客户端编码必须配置) * 1、项目秘钥配置【使用SM4加密传输数据,SM2传输秘钥为例】 ```java @Configuration public class DataSecurityConfig { @Bean public SecretConfig secretConfig() { return SecretConfig.builder() .reqAlgorithm(SecretAlgorithm.SM4_CBC_PKCS7) .requestAsymmetricMode(RequestAsymmetricMode.SM2_WITH_SESSION) .dbSecretKey("数据存储加密秘钥") // 不使用可以不配置 // 数据存储加解密算法 .dbAlgorithm(SecretAlgorithm.PKCS7) // 不使用可以不配置 .clientCode("system") // 客户端编码 .build(); } } ``` * 2、前端获取公钥 ```html Get: localhost:9898/data-security/api/asymmetricTSC/public-key Response响应数据: { "publicKey": "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEFgFkoXDTKyP2jhigRUlrI3qO0LxZ3emioBNS8ReMYW19PMSEw+90mWmWBDcF8h0eUwDmpMWaXApfX2vRWWfwtw==", "version": "c72255c86c5f4993b39dea9458140fd7" } ``` * 3、前端使用公钥加密私钥 --自定义方法处理 * 4、获取请求会话 ```html Post: localhost:9898/data-security/api/asymmetricTSC/create-session Header请求头: X-Client-Key:BLhIkXkGvHfPaTZq8MmWXys3BVa2bznqS0j/seGtmHYSqbcU1kUKtG2RnhtXbNoq8xD+HIsImQKyqPTz8KIGiqY9gvDEPuVFxpI/lZAI2rbT3yflfgOWG7OfLRn54q0Y6zhb6vKIzWJfup5RW1RqFUiItikGkh+z9JA5PY+mo7de X-Timestamp: 1752459639000 Response响应数据: { "expiresIn": 7789, "publicKeyVersion": "c72255c86c5f4993b39dea9458140fd7", "sessionId": "224a47ff805f41738c1f78e160c6534e" } ``` * 5、请求数据传输用例(采用16进制的IV模式,base64的IV请参考:动态Base64编码IV,前端用ApiPost模拟) | 步骤 | 处理方法 | |:------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 参数加密 | // 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba7896543210"; // 必须是16字节(128位)
// 生成 16 字节随机 IV(以 WordArray 格式表示)
var iv = CryptoJS.lib.WordArray.random(16);
// 转换为十六进制字符串(可读性更好)
var ivHex = iv.toString(CryptoJS.enc.Hex);
// 请求前脚本 - SM4加密请求数据并以Base64格式输出
function encryptData(word, key, iv) {
    // 如果数据是对象,转换为JSON字符串
    // 使用SM4-CBC模式加密
    let encryptedHex = sm4.encrypt(word, key, { mode: 'cbc', iv: iv }) // 加密,cbc 模式
    // 将16进制字符串转换为字节数组
    var bytes = hexToBytes(encryptedHex);
    // 将字节数组转换为Base64
    var encryptedBase64 = bytesToBase64(bytes);
    return encryptedBase64;
}

// 辅助函数:16进制字符串转字节数组
function hexToBytes(hex) {
    var bytes = [];
    for (var i = 0; i < hex.length; i += 2) {
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }
    return bytes;
}
// 辅助函数:字节数组转Base64
function bytesToBase64(bytes) {
    var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    var result = '';
    var i = 0;

    while (i < bytes.length) {
        var byte1 = bytes[i++];
        var byte2 = i < bytes.length ? bytes[i++] : 0;
        var byte3 = i < bytes.length ? bytes[i++] : 0;

        var enc1 = byte1 >> 2;
        var enc2 = ((byte1 & 0x03) << 4) \| (byte2 >> 4);
        var enc3 = ((byte2 & 0x0F) << 2) \| (byte3 >> 6);
        var enc4 = byte3 & 0x3F;

        if (i > bytes.length + 1) {
            enc3 = enc4 = 64;
        } else if (i > bytes.length) {
            enc4 = 64;
        }

        result += base64Chars.charAt(enc1) + base64Chars.charAt(enc2) +
            base64Chars.charAt(enc3) + base64Chars.charAt(enc4);
    }

    return result;
}
// 获取请求数据
var requestData = pm.request.body.raw;
let encryptedData = encryptData(requestData, secretKey, ivHex);
// 设置加密后的数据到请求体
pm.request.body.raw = encryptedData;
// 可选:添加加密信息头
pm.request.headers.upsert({
    key: 'X-Encrypted-IV',
    value: ivHex
});
| | 请求数据 | POST: localhost:9898/data-security/account/getInfoByWrapper
Header: X-Encrypted-SessionId: 224a47ff805f41738c1f78e160c6534e(会话id)
RequestBody请求数据:
FzW0t8uo9sWxEgj+CBXspDBk5A0EthEvjnFT1z5ecOa1oUmsNfUQhTa3hdVQYS0W
ResponseBody: "tHgZ5ENlVhWq6QGmaaNRJy/DjU+1datQ2EiteFD9fAltwRR8EwX3gzROm1HwCa4hq8GOS+JMa64kcgrYzZ1WPRvqCw+Y6jEeOcgiNAxCAchN23Mv/dob0aeM4CwI5pzx1QGBsGJeTLle5Dv9oDkTyg=="
| | 返回数据解密 | // 响应后脚本 - 解密SM4加密的响应数据
// 设置你的密钥和IV(实际项目中应从配置或环境变量获取)
var secretKey = "0123456789abcdeffedcba7896543210"; // 必须是16字节(128位)
function decryptData(ciphertext, key, iv) {
    // 使用SM4-CBC模式解密
    let decryptStr = ciphertext.replaceAll("\"", "");
    // 将Base64转换为字节数组
    var ciphertextBytes = base64ToBytes(decryptStr);
    // 将字节数组转换为16进制字符串
    var ciphertextHex = bytesToHex(ciphertextBytes);
    // 使用SM4-CBC模式加密
    var decryptedResult = sm4.decrypt(ciphertextHex, key, { mode: 'cbc', iv: iv })
    return decryptedResult;
}
// 辅助函数:Base64转字节数组
function base64ToBytes(base64) {
    var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    base64 = base64.replace(/=+$/, '');
    var bytes = [];
    for (var i = 0; i < base64.length; i += 4) {
        var enc1 = base64Chars.indexOf(base64.charAt(i));
        var enc2 = base64Chars.indexOf(base64.charAt(i + 1));
        var enc3 = base64Chars.indexOf(base64.charAt(i + 2));
        var enc4 = base64Chars.indexOf(base64.charAt(i + 3));

        var byte1 = (enc1 << 2) \| (enc2 >> 4);
        var byte2 = ((enc2 & 0x0F) << 4) \| (enc3 >> 2);
        var byte3 = ((enc3 & 0x03) << 6) \| enc4;

        bytes.push(byte1);
        if (enc3 !== 64) bytes.push(byte2);
        if (enc4 !== 64) bytes.push(byte3);
    }

    return bytes;
}
// 辅助函数:字节数组转16进制字符串
function bytesToHex(bytes) {
    var hex = [];
    for (var i = 0; i < bytes.length; i++) {
        var b = bytes[i];
        hex.push((b < 16 ? '0' : '') + b.toString(16));
    }
    return hex.join('');
}
// 获取响应数据
var responseData = pm.response.text();
const envIV = pm.response.headers.get('X-Encrypted-IV');
// 解密数据
var decryptedData = decryptData(responseData, secretKey, envIV);
// 尝试解析为JSON(如果是JSON格式)
try {
    var jsonData = JSON.parse(decryptedData);
    pm.response.json = function () { return jsonData; };
} catch (e) {
    // 如果不是JSON,保留原始解密文本
    pm.response.text = function () { return decryptedData; };
}
// 记录解密结果到控制台
console.log("解密响应:", decryptedData);
| # 问题排查 + Expected parsed RequestPath in request attribute "org.springframework.web.util.ServletRequestPathUtils.PATH". 修改路径解析的方式 ``` yaml spring: mvc: pathmatch: matching-strategy: ant_path_matcher ```