# spring-boot-interface-crypto **Repository Path**: fastiot/spring-boot-interface-crypto ## Basic Information - **Project Name**: spring-boot-interface-crypto - **Description**: springboot对API接口进行统一加解密 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 4 - **Created**: 2022-06-12 - **Last Updated**: 2022-06-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # spring-boot-interface-crypto ## 介绍 springboot对API接口进行统一加解密 ## 实现思路 1. 设置启动加解密API请求或响应 2. 编写`RequestBodyAdvice`及`ResponseBodyAdvice`实现 3. supports引入是否加解密 4. 实现`beforeBodyRead` `beforeBodyWrite` 5. 不同方式实现加解密(动态key) ## 加密解密支持 - 可进行加密的方式有: - - [x] AES - - [x] DES - - [x] RSA - - [x] Base64 - - [x] SM2 - - [x] SM4 - 可进行解密的方式有: - - [x] AES - - [x] DES - - [x] RSA - - [x] Base64 - - [x] SM2 - - [x] SM4 ## 使用方法 - 参数配置 在项目的`application.yml`或`application.properties`文件中进行参数配置,例如: ```yaml crypto: configs: - type: aes key: 2691b31aa11bee4b62c05537aa67558a - type: des key: 9e07b5136216fd6b - type: rsa public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgQq2HopByR9b5Pcj4IMSzF5F7YUeq0RGd/oIlzkyNHxUqV6FXEzTCPmSA+P0r6b9zSF2fVwXdDIy2kTTNffFQvUfP/eEUBw9ULFl4BhEygkQCInCTISkQs8Sx24jDQyY1P0IzkWjjjYtka2/bWcu9euPDAagZl6/KPMM8kI9RPwIDAQAB private-key: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKBCrYeikHJH1vk9yPggxLMXkXthR6rREZ3+giXOTI0fFSpXoVcTNMI+ZID4/Svpv3NIXZ9XBd0MjLaRNM198VC9R8/94RQHD1QsWXgGETKCRAIicJMhKRCzxLHbiMNDJjU/QjORaOONi2Rrb9tZy71648MBqBmXr8o8wzyQj1E/AgMBAAECgYAaH/SA3V/VuV9Sfx9xT4oxNcDaD5gqwO0xx8j4l8JD6RK+tc1P0Ao0Ng6VNcGztGWoyd21OW7zw3V214H3k7XQNQdm1xYFbYuzTN9YokQrEc7zjUSDdxh/f2QuH8N0Btr7FkOT+7vba5f/keim2IcmWNYVrTdCkAOtQnsJvYqBMQJBANQHkG34dTtiSBmTgTAg/1hwCOUSPy8f0Kf57TeHAWC+Pzm4tmYrg9aqU9fvppZaFTiHnmJGvP4AXwExeoHH0m8CQQDBfr6rewFEQCeaqMpDag0vE0LVljCutxsG8ouEIqN0/pzXKpGc99T5eNZZrLvVf+TP3sjaKTxREvaUvM0BrZYxAkEAgcATQUi/LNTq/EPI1dQLjmoY911gLw1QGcsWwFksnbAubrs7W3CboDzhTA5Kqk18GPjdEpTpSKKfgNJvfoXynwJAZvYDjYn5hZDBwjlYz4CKHWeZY7/0jbOfbRX5CUnJQsMNQC1FqInzyP/0x2jz1kqkvbvlkrjogJefoEvKpr7wsQJAPNg/cc71wB4MEUJPJopxR2yr1yS1kO0491iwh21cvR3W8fQMYW59fl6LvwGVfO/BhukZ16+KEnQVvcm2yD/rHQ== - type: sm2 public-key: MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEilivBGPrnunZqZL9Coa+Ir4p63nPgAS95oYFaKYPd+BKHbouiqRMd/WPgwFnZSdPZ1IRrM3TNlHdO65plFwNDw== private-key: MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQggz7cN/iSujCLHhGaW8PPHuHiFWHgQJwIVtth/85zQ5GgCgYIKoEcz1UBgi2hRANCAASKWK8EY+ue6dmpkv0Khr4ivinrec+ABL3mhgVopg934Eodui6KpEx39Y+DAWdlJ09nUhGszdM2Ud07rmmUXA0P - type: sm4 key: ea3f9e5432e4f21d4b01a4e6a6ee95be - type: rc2 key: N1KBLtE9GzFqcEvuyDjBAA== scan-outer-package: com.hzhh123.sample.crypto #外部扫描加密类 ``` 加密key的生成使用Sm2Utils.java、Sm4Utils.java、RsaUtils.java、AesUtils.java、DesUtils.java生成,生成的key转base64或hex值,key是hex值的加密后的 值也是hex值,key是base64的则加密后的值也是base64值,其中AES、DES、SM4是对称加密,加解密直接设置key值,publicKey和privateKey值不用设置,非对称加密RSA、SM2需要设置公私钥,key不用设置。 scan-outer-package是扩展加密方式所扫描的外部包,实现原理是继承了EnvironmentAware,BeanFactoryPostProcessor接口environment通过scan-outer-package获取外部加解密扫描包,代码如下: ```java package com.hzhh123.crypto.processor; import com.hzhh123.crypto.annotation.CryptoType; import com.hzhh123.crypto.handle.CryptoContext; import com.hzhh123.crypto.utils.spring.ClassScanner; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import java.util.HashMap; import java.util.Map; /** * @author hzhh123 * @version 1.0 * @date 2022/4/15 17:00 * @des */ @Slf4j public class CryptoBeanFactoryPostProcessor implements EnvironmentAware,BeanFactoryPostProcessor { private final static String HANDLE_PACKAGE = "com.hzhh123.crypto.handle"; @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { Map> handleMap = new HashMap<>(8); ClassScanner.scan(HANDLE_PACKAGE, CryptoType.class).forEach(clazz -> { String value = clazz.getAnnotation(CryptoType.class).value(); handleMap.put(value, clazz); }); //扫描外部包,直接从CryptoProperties中获取不到属性 String scanOuterCryptoPackage = environment.getProperty("crypto.scan-outer-package"); if(StringUtils.isNotBlank(scanOuterCryptoPackage)){ log.info("扫描加解密外部包(crypto.scan-outer-package){}",scanOuterCryptoPackage); String[] scanOuterCryptoPackages = scanOuterCryptoPackage.split(","); ClassScanner.scan(scanOuterCryptoPackages, CryptoType.class).forEach(clazz -> { String value = clazz.getAnnotation(CryptoType.class).value(); handleMap.put(value, clazz); }); } log.info("默认支持加解密方式:{}",handleMap.keySet()); CryptoContext cryptoContext = new CryptoContext(handleMap); configurableListableBeanFactory.registerSingleton(CryptoContext.class.getName(), cryptoContext); } private ConfigurableEnvironment environment; @Override public void setEnvironment(Environment environment) { this.environment = (ConfigurableEnvironment) environment; } } ``` 扩展加解密类,继承AbstractCrypto类,实现encryot和decrypt方法 ```java package com.hzhh123.sample.crypto; import com.hzhh123.crypto.annotation.CryptoType; import com.hzhh123.crypto.config.CryptoProperties; import com.hzhh123.crypto.exception.EncryptException; import com.hzhh123.crypto.handle.AbstractCrypto; import com.hzhh123.crypto.utils.CryptoPropertiesUtils; import com.hzhh123.crypto.utils.RC2Utils; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * @author hzhh123 * @version 1.0 * @date 2022/4/15 21:40 * @des */ @RequiredArgsConstructor(onConstructor_ = @Autowired) @Component @CryptoType("RC2") public class RC2CryptoHandle extends AbstractCrypto { private final CryptoProperties cryptoProperties; @Override public String encrypt(String str) { CryptoProperties.PairKey cryptoPropertiesPairKey = getCryptoPropertiesPairKey(); return RC2Utils.encrypt(str,cryptoPropertiesPairKey.getKey()); } @Override public String decrypt(String str) { CryptoProperties.PairKey cryptoPropertiesPairKey = getCryptoPropertiesPairKey(); return RC2Utils.decrypt(str,cryptoPropertiesPairKey.getKey()); } private CryptoProperties.PairKey getCryptoPropertiesPairKey() { CryptoProperties.PairKey cryptoPropertiesPairKey = CryptoPropertiesUtils.getCryptoPropertiesPairKey("RC2", cryptoProperties); if (cryptoPropertiesPairKey == null) { throw new EncryptException("RC2加密KEY不能为空"); } if (cryptoPropertiesPairKey.getKey() == null) { throw new EncryptException("RC2加密KEY不能为空"); } return cryptoPropertiesPairKey; } } ``` ## 其他参考 - [源码-参考](https://gitee.com/licoy/encrypt-body-spring-boot-starter) - [源码-参考](https://gitee.com/springboot-hlh/spring-boot-csdn.git) ## 测试 [GET]http://localhost:8080/test1 json请求参数: ```json { "data":"1b400e753dc2cfa01d98caeb23b07172509226bbf24749972486bf44cf35d2b476bb627708ccf9b140f527dd570d3a3e7a0cb9f469a917be229d8181956aef9f" } ``` 响应: ```json { "code": "200", "data": "cUpvgQrr2elOOnVFvsqhn6vrxHJWpE7xr5oeoEyVyDy/eQbeosO8g1mDz6WsgVNCWNCpNZdPd7GYy586GwCVFdIUN9N5SICVOTHErgPeqHLGR3fdvjbL6feGrUNbxHTGJhVgwhBq8ljEUoaXXqTpfkwKznBUakgzKlTBa/yZ4bM=", "success": true, "message": "成功", "timestamp": 1650008249034 } ``` 请求代码 ```java /** * 请求参数{"data":"AES加密User实例json数据"},响应结果RSA加密 */ @Slf4j @RestController @Decrypt(type = EncrptyTypeEnum.AES) @Encrypt(type = EncrptyTypeEnum.RSA) public class Test1Controller implements ResultBuilder { @GetMapping("/test1") public ResponseEntity> test1(@RequestBody User user){ log.info("{}",user); return success(user); } } 或 /** * @author hzhh123 * @version 1.0 * @date 2022/4/13 14:47 * @des * * */ @Slf4j @RestController @Decrypt(type = EncrptyTypeEnum.AES) @Encrypt("SM2") //@Base64Encrypt public class Test1Controller implements ResultBuilder { @GetMapping("/test1") public ResponseEntity> test1(@RequestBody User user){ log.info("{}",user); return success(user); } } ```