MyBatis-Plus数据安全保护(加密解密)
- 项目创建
- POM依赖
<dependency><!--MyBatis-Plus 企业级模块--> <groupId>com.baomidou</groupId> <artifactId>mybatis-mate-starter</artifactId> <version>1.2.8</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bctls-jdk15on --> <dependency><!--SM2 SM3 SM4 加密算法依赖--> <groupId>org.bouncycastle</groupId> <artifactId>bctls-jdk15on</artifactId> <version>1.70</version> </dependency> <!-- https://mvnrepository.com/artifact/org.jasypt/jasypt --> <dependency><!--混合加密算法依赖--> <groupId>org.jasypt</groupId> <artifactId>jasypt</artifactId> <version>1.9.3</version> </dependency>
- YML配置
spring: datasource: # 配置安全:https://blog.csdn.net/tongxin_tongmeng/article/details/128664932 url: mpw:IlcV2VrLIr+z3ruf0oHP1sV3JuEvntw9QZDEYhQWDNHJ9Xkm7qZokxkEeTCPNqma username: mpw:aoVz0lDJNymnmrhw6LkQow== password: mpw:StRVtLG7vB6iKVt83du7fw== driver-class-name: com.mysql.cj.jdbc.Driver # Mybatis Mate 配置 mybatis-mate: cert: # 请添加微信wx153666购买授权,不白嫖从我做起! 测试证书会失效,请勿正式环境使用 grant: thisIsTestLicense license: TtY9GC88CzSkEmUhzIyvM2MJKvsgPyxoNCExH4/GhaBwuTQ93aeLaR6/dM49wMSk+oQdmqUibCM8b5H74s1Nx+2C5V3U1gKiLtddVc8Eg8oC1F2nLxOiDKDvPpdxWFGsPW6mQE2LDr+tK8GXpFS3N8xwmYy/gHCwQ4Avqp9JqBbke7pZzL2adIlxYHmCYpfNTN+NRHIEFaGFTBlzZHDb3UfJaeqLaAtWBol0QOPEM69Kz3JSemxBHnEO1ID75bwwmkgqC7Ps4z9iYAK9GLzzaPwSiFELNCmIvwa5YSJLxP9NMQUWbVGIRqehxnVqfgx/68+yIfpByqGTMxLR33yeEQ== # 全局配置加密算法密钥 encryptor: # MD5_32 MD5_16 BASE64 AES SM2 SM3 SM4 需要 password,其他加密算法需要 password publicKey privateKey password: mybatis-mate-encryptor-password-666 publicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCEOCMScPeNaJ0DP9N9vd/fXwPGUVnuxeGPpRePXfWuX/X/Yk5IMhwEfYLXictxQk/oAqGnqtDuS/PCL/7mqL+8wFSYnWWErCSkDdT6LjyD07l9dWv+Xj1UTEjP24sEgYA92f4AZyvhsw8I/Bj6a9a30r+kVOGoEZgGMf2c2xK4CQIDAQAB privateKey: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIQ4IxJw941onQM/0329399fA8ZRWe7F4Y+lF49d9a5f9f9iTkgyHAR9gteJy3FCT+gCoaeq0O5L88Iv/uaov7zAVJidZYSsJKQN1PouPIPTuX11a/5ePVRMSM/biwSBgD3Z/gBnK+GzDwj8GPpr1rfSv6RU4agRmAYx/ZzbErgJAgMBAAECgYBAlFK9DSQ8k14tWh1oizcvmO71DIMKluhHCvHo+pGnLAOxS0jFBoScxNkFga42kZcJ0U8337zQx5Q1ws+TxdRwHxQO889ZGQH3kOFB0ErUMTgFrTOakZhV0dMWzebkYitNcduSKZ1yfgM5ekF9k3owPIQhUNy8eXjagiLLb9/woQJBALwofOx+fuanQLC1yotFqYAx0XED9EpVPhS/G8mc4dZSNWZ548bIyq3ozP0CoHqriQo/X3NVzIJOU3rhn92fwj0CQQCz5FaeHzSqe1H4bTxzwgR5BUHttxrAPtktwfgCRgaSrZByjFldtP/dGaJmjR2Vzp848WcusJZlSlaLTfndm6W9AkEAoSxlZgctGNKn3Ta7mvU/Lmp+J7rlZU8DcK4LVXYnFXkx+OfsLvkMdE/4V7oKUUnih36lepxCJFSHubjPQf55WQJBAIUa8yxUkreCQAi9avmMGZsiVMH7tgOBfVjqKQQlpD9rxXG8f3Nitd93VD7lM3rhQ9byaBKX/vA7rQWuUK+0t1ECQDTGhLRJFZK4J7UGklTX94pknM/5rO3N/JPkFJcGilbgzkqy0s13D1K+8cR0qTn2DPW8vPoLQpVGuaATTTmMdvg=
@SpringBootTest class MybatisPlusApplicationTests { @Test void contextLoads() throws Exception { Map<String, Key> keyMap = RSA.genKeyPair(); String publicKey = RSA.getPublicKey(keyMap); String privateKey = RSA.getPrivateKey(keyMap); System.out.println("publicKey========="+publicKey); System.out.println("privateKey========="+privateKey); } } 注意:password为任意字符串,publicKey和privateKey通过如上方法生成
- SQL脚本
CREATE TABLE `encrypt` ( `id` bigint NOT NULL COMMENT '主键ID', `MD5_32` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'MD5_32', `MD5_16` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'MD5_16', `BASE64` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'BASE64', `AES` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'AES', `RSA` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'RSA', `SM2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'SM2', `SM3` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'SM3', `SM4` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'SM4', `PBEWithMD5AndDES` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'PBEWithMD5AndDES', `PBEWithMD5AndTripleDES` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'PBEWithMD5AndTripleDES', `PBEWithHMACSHA512AndAES_256` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'PBEWithHMACSHA512AndAES_256', `PBEWithSHA1AndDESede` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'PBEWithSHA1AndDESede', `PBEWithSHA1AndRC2_40` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'PBEWithSHA1AndRC2_40', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
- 代码生成(MybatisX)
@RestController @RequestMapping("/encrypt") public class EncryptController { @Autowired private EncryptService encrtptService; @PostMapping("/create") public Boolean create(@RequestBody Encrypt encrypt) { return encrtptService.save(encrypt); } @GetMapping("/get") public Encrypt get(@RequestBody Encrypt encrypt) { return encrtptService.getById(encrypt.getId()); } @GetMapping("/getAll") public List<Encrypt> getAll() { return encrtptService.list(); } @PutMapping("/update") public Boolean update(@RequestBody Encrypt encrypt) { return encrtptService.updateById(encrypt); } @DeleteMapping("/delete") public Boolean delete(@RequestBody Encrypt encrypt) { return encrtptService.removeById(encrypt); } @DeleteMapping("/deleteAll") public Boolean deleteAll() { return encrtptService.remove(new QueryWrapper<>()); } }
- 加密算法
- 字段加密(@FieldEncrypt)
/** * * @TableName encrypt */ @TableName(value ="encrypt") @Data public class Encrypt implements Serializable { /** * 主键ID */ @TableId(value = "id") private Long id; /** * MD5_32 */ @FieldEncrypt(algorithm = Algorithm.MD5_32) @TableField(value = "MD5_32") private String md532; /** * MD5_16 */ @FieldEncrypt(algorithm = Algorithm.MD5_16) @TableField(value = "MD5_16") private String md516; /** * BASE64 */ @FieldEncrypt(algorithm = Algorithm.BASE64) @TableField(value = "BASE64") private String base64; /** * AES */ @FieldEncrypt(algorithm = Algorithm.AES) @TableField(value = "AES") private String aes; /** * RSA */ @FieldEncrypt(algorithm = Algorithm.RSA) @TableField(value = "RSA") private String rsa; /** * SM2 */ @FieldEncrypt(algorithm = Algorithm.SM2) @TableField(value = "SM2") private String sm2; /** * SM3 */ @FieldEncrypt(algorithm = Algorithm.SM3) @TableField(value = "SM3") private String sm3; /** * SM4 */ @FieldEncrypt(algorithm = Algorithm.SM4) @TableField(value = "SM4") private String sm4; /** * PBEWithMD5AndDES */ @FieldEncrypt(algorithm = Algorithm.PBEWithMD5AndDES) @TableField(value = "PBEWithMD5AndDES") private String pbewithmd5anddes; /** * PBEWithMD5AndTripleDES */ @FieldEncrypt(algorithm = Algorithm.PBEWithMD5AndTripleDES) @TableField(value = "PBEWithMD5AndTripleDES") private String pbewithmd5andtripledes; /** * PBEWithHMACSHA512AndAES_256 */ @FieldEncrypt(algorithm = Algorithm.PBEWithHMACSHA512AndAES_256) @TableField(value = "PBEWithHMACSHA512AndAES_256") private String pbewithhmacsha512andaes256; /** * PBEWithSHA1AndDESede */ @FieldEncrypt(algorithm = Algorithm.PBEWithSHA1AndDESede) @TableField(value = "PBEWithSHA1AndDESede") private String pbewithsha1anddesede; /** * PBEWithSHA1AndRC2_40 */ @FieldEncrypt(algorithm = Algorithm.PBEWithSHA1AndRC2_40) @TableField(value = "PBEWithSHA1AndRC2_40") private String pbewithsha1andrc240; @TableField(exist = false) private static final long serialVersionUID = 1L; @Override public boolean equals(Object that) { if (this == that) { return true; } if (that == null) { return false; } if (getClass() != that.getClass()) { return false; } Encrypt other = (Encrypt) that; return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) && (this.getMd532() == null ? other.getMd532() == null : this.getMd532().equals(other.getMd532())) && (this.getMd516() == null ? other.getMd516() == null : this.getMd516().equals(other.getMd516())) && (this.getBase64() == null ? other.getBase64() == null : this.getBase64().equals(other.getBase64())) && (this.getAes() == null ? other.getAes() == null : this.getAes().equals(other.getAes())) && (this.getRsa() == null ? other.getRsa() == null : this.getRsa().equals(other.getRsa())) && (this.getSm2() == null ? other.getSm2() == null : this.getSm2().equals(other.getSm2())) && (this.getSm3() == null ? other.getSm3() == null : this.getSm3().equals(other.getSm3())) && (this.getSm4() == null ? other.getSm4() == null : this.getSm4().equals(other.getSm4())) && (this.getPbewithmd5anddes() == null ? other.getPbewithmd5anddes() == null : this.getPbewithmd5anddes().equals(other.getPbewithmd5anddes())) && (this.getPbewithmd5andtripledes() == null ? other.getPbewithmd5andtripledes() == null : this.getPbewithmd5andtripledes().equals(other.getPbewithmd5andtripledes())) && (this.getPbewithhmacsha512andaes256() == null ? other.getPbewithhmacsha512andaes256() == null : this.getPbewithhmacsha512andaes256().equals(other.getPbewithhmacsha512andaes256())) && (this.getPbewithsha1anddesede() == null ? other.getPbewithsha1anddesede() == null : this.getPbewithsha1anddesede().equals(other.getPbewithsha1anddesede())) && (this.getPbewithsha1andrc240() == null ? other.getPbewithsha1andrc240() == null : this.getPbewithsha1andrc240().equals(other.getPbewithsha1andrc240())); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); result = prime * result + ((getMd532() == null) ? 0 : getMd532().hashCode()); result = prime * result + ((getMd516() == null) ? 0 : getMd516().hashCode()); result = prime * result + ((getBase64() == null) ? 0 : getBase64().hashCode()); result = prime * result + ((getAes() == null) ? 0 : getAes().hashCode()); result = prime * result + ((getRsa() == null) ? 0 : getRsa().hashCode()); result = prime * result + ((getSm2() == null) ? 0 : getSm2().hashCode()); result = prime * result + ((getSm3() == null) ? 0 : getSm3().hashCode()); result = prime * result + ((getSm4() == null) ? 0 : getSm4().hashCode()); result = prime * result + ((getPbewithmd5anddes() == null) ? 0 : getPbewithmd5anddes().hashCode()); result = prime * result + ((getPbewithmd5andtripledes() == null) ? 0 : getPbewithmd5andtripledes().hashCode()); result = prime * result + ((getPbewithhmacsha512andaes256() == null) ? 0 : getPbewithhmacsha512andaes256().hashCode()); result = prime * result + ((getPbewithsha1anddesede() == null) ? 0 : getPbewithsha1anddesede().hashCode()); result = prime * result + ((getPbewithsha1andrc240() == null) ? 0 : getPbewithsha1andrc240().hashCode()); return result; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); sb.append(" ["); sb.append("Hash = ").append(hashCode()); sb.append(", id=").append(id); sb.append(", md532=").append(md532); sb.append(", md516=").append(md516); sb.append(", base64=").append(base64); sb.append(", aes=").append(aes); sb.append(", rsa=").append(rsa); sb.append(", sm2=").append(sm2); sb.append(", sm3=").append(sm3); sb.append(", sm4=").append(sm4); sb.append(", pbewithmd5anddes=").append(pbewithmd5anddes); sb.append(", pbewithmd5andtripledes=").append(pbewithmd5andtripledes); sb.append(", pbewithhmacsha512andaes256=").append(pbewithhmacsha512andaes256); sb.append(", pbewithsha1anddesede=").append(pbewithsha1anddesede); sb.append(", pbewithsha1andrc240=").append(pbewithsha1andrc240); sb.append(", serialVersionUID=").append(serialVersionUID); sb.append("]"); return sb.toString(); } }
- 加密测试
加密前: { "md532": "md532", "md516": "md516", "base64": "base64", "aes": "aes", "rsa": "rsa", "sm2": "sm2", "sm3": "sm3", "sm4": "sm4", "pbewithmd5anddes": "pbewithmd5anddes", "pbewithmd5andtripledes": "pbewithmd5andtripledes", "pbewithhmacsha512andaes256": "pbewithhmacsha512andaes256", "pbewithsha1anddesede": "pbewithsha1anddesede", "pbewithsha1andrc240": "pbewithsha1andrc240" } 注意:调用控制器接口向数据库插入数据
加密后: { "id": "1614832069533679617", "md532": "0ed5449e148dfaac16d1247667d62554", "md516": "838026c17d7ac626", "base64": "YmFzZTY0", "aes": "3420e2d91b8f913bb035258e5013cc6f", "rsa": "FqVQIe05Q/usNmZZWA9omCf63WYbhT7z4Qsrpvr+RsWv70vV3hVK5sV1/HZvQL6uI9pU0dkdPDEwIzn0DCJIoVKCW3l7fubdOkjOgaqxv5tIdcLmZFl9XivzA6sDhSIzitFLAj4OJu2HgbF1fNDoVEdYqAD7BEMeNeCyQYyjNQk=", "sm2": "sm2", "sm3": "d0c7f21dc640a69786764d688920d4d968a103a437a6159b9e7cc7c4b826b8ac", "sm4": "sm4", "pbewithmd5anddes": "q30eLvs6615ATdqtscdIpSdZLgC+vg1/+8mLzeD2INo=", "pbewithmd5andtripledes": "PjjKX2OkRE2D/mz3UZLTXXAsLkjuAk6rF8l4WVz/CaE=", "pbewithhmacsha512andaes256": "N5GESK0bGjLsJGO4DadbUMNzPo6ov/svzNHCZg0S4gmrsMLSDMLHDO/6ZrPNsYhpBTR53Xmksi9fxwSU5ScshQ==", "pbewithsha1anddesede": "1kGvVHNUKDbwYG1ZnLhaK2QPre3jFddM3tB6MQETzwE=", "pbewithsha1andrc240": "my9MZrkBSRtwgV6/MjAjwug7HB/lKHTMzmZJeUOrCQY=" } 注意:数据库存储内容为密文,其中SM2与SM4加密失败,其他算法加密成功
解密后: { "id": 1614832069533679617, "md532": "0ed5449e148dfaac16d1247667d62554", "md516": "838026c17d7ac626", "base64": "base64", "aes": "aes", "rsa": "rsa", "sm2": "sm2", "sm3": "d0c7f21dc640a69786764d688920d4d968a103a437a6159b9e7cc7c4b826b8ac", "sm4": "sm4", "pbewithmd5anddes": "pbewithmd5anddes", "pbewithmd5andtripledes": "pbewithmd5andtripledes", "pbewithhmacsha512andaes256": "pbewithhmacsha512andaes256", "pbewithsha1anddesede": "pbewithsha1anddesede", "pbewithsha1andrc240": "pbewithsha1andrc240" } 注意:调用控制器接口查询数据,查询结果为加密前数据,其中MD5_32 MD5_16 SM3仍是密文,说明这三种算法不可逆
-
自定义算法
注意:自定义加密算法需实现IEncryptor接口,IEncryptor接口可有多个实现类,但只能有一个实现类添加@Component注解,添加 @Component注解便启用自定义加密算法,一旦启用自定义加密算法,那么项目中所有@FieldEncrypt加密的字段都将使用自定义加密 算法进行加密,其他算法均不再生效,如下CustomEncryptor自定义加密算法,加密时"##$$##=="+plaintext+"--&&$$&&"实现加密, 解密时encrypt.replace("##$$##==", "").replace("--&&$$&&", "")实现解密
// 自定义加密算法,这里为开启使用默认加密库 @Component public class CustomEncryptor implements IEncryptor { /** * 加密 * * @param algorithm 算法 * @param password 密码(对称加密算法密钥) * @param plaintext 明文 * @param publicKey 非对称加密算法(公钥) * @param metaObject {@link MetaObject} * @return */ @Override public String encrypt(Algorithm algorithm, String password, String publicKey, String plaintext, Object metaObject) { if (metaObject instanceof MetaObject) { // _metaObject为加密字段所属对象,可通过已知属性名获取属性值,_metaObject.getValue("属性名") MetaObject _metaObject = ((MetaObject) metaObject); } return "##$$##=="+plaintext+"--&&$$&&"; } /** * 解密 * * @param algorithm 算法 * @param password 密码(对称加密算法密钥) * @param encrypt 密文 * @param privateKey 非对称加密算法(私钥) * @param metaObject {@link MetaObject} * @return */ @Override public String decrypt(Algorithm algorithm, String password, String privateKey, String encrypt, Object metaObject) { if (metaObject instanceof MetaObject) { // _metaObject为加密字段所属对象,可通过已知属性名获取属性值,_metaObject.getValue("属性名") MetaObject _metaObject = ((MetaObject) metaObject); } return encrypt.replace("##$$##==", "").replace("--&&$$&&", ""); } }