!274 add 新增 基于 Mybatis 实现数据库字段加解密功能

This commit is contained in:
_老马_
2023-01-18 04:13:43 +00:00
committed by 疯狂的狮子Li
parent 540afd839d
commit e20dacbfd9
22 changed files with 1129 additions and 0 deletions

View File

@ -0,0 +1,44 @@
package com.ruoyi.common.annotation;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
import java.lang.annotation.*;
/**
* 字段加密注解
*
* @author 老马
*/
@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
/**
* 加密算法
*/
AlgorithmType algorithm() default AlgorithmType.BASE64;
/**
* 秘钥。AES、SM4需要
*/
String password() default "";
/**
* 公钥。RSA、SM2需要
*/
String publicKey() default "";
/**
* 公钥。RSA、SM2需要
*/
String privateKey() default "";
/**
* 编码方式。对加密算法为BASE64的不起作用
*/
EncodeType encode() default EncodeType.BASE64;
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.common.encrypt;
import com.ruoyi.common.enums.EncodeType;
import lombok.Builder;
import lombok.Data;
/**
* 加密上下文。用于encryptor传递必要的参数。
* 隔离配置和注解
*
* @author 老马
* @date 2023-01-17 08:31
*/
@Data
public class EncryptContext {
/**
* 安全秘钥
*/
private String password;
/**
* 公钥
*/
private String publicKey;
/**
* 私钥
*/
private String privateKey;
/**
* 编码方式base64/hex
*/
private EncodeType encode;
}

View File

@ -0,0 +1,46 @@
package com.ruoyi.common.encrypt;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
/**
* 加解者
*
* @author 老马
* @date 2023-01-10 16:08
*/
public interface IEncryptor {
/**
* 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/
AlgorithmType algorithm();
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String 加密后的字符串
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/
String encrypt(String value, EncodeType encodeType) throws Exception;
/**
* 解密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String 解密后的字符串
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/
String decrypt(String value, EncodeType encodeType) throws Exception;
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.common.encrypt.encryptor;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.encrypt.IEncryptor;
/**
* 所有加密执行者的基类
*
* @author 老马
* @date 2023-01-17 16:52
*/
public abstract class AbstractEncryptor implements IEncryptor {
public AbstractEncryptor(EncryptContext context) {
//子类必须实现带参数的构造方法
}
}

View File

@ -0,0 +1,87 @@
package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
import java.nio.charset.StandardCharsets;
/**
* AES算法实现
*
* @author 老马
* @date 2023-01-06 11:39
*/
public class AesEncryptor extends AbstractEncryptor {
private AES aes = null;
public AesEncryptor(EncryptContext context) {
super(context);
String password = context.getPassword();
if (StrUtil.isBlank(password)) {
throw new RuntimeException("aes没有获得秘钥信息");
}
// aes算法的秘钥要求是16位、24位、32位
int[] array = {16, 24, 32};
if(!ArrayUtil.contains(array, password.length())) {
throw new RuntimeException("aes秘钥长度应该为16位、24位、32位实际为"+password.length()+"");
}
aes = SecureUtil.aes(context.getPassword().getBytes(StandardCharsets.UTF_8));
}
/**
* 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/
@Override
public AlgorithmType algorithm() {
return AlgorithmType.AES;
}
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String encrypt(String value, EncodeType encodeType) throws Exception {
if (ObjectUtil.isNotNull(this.aes)) {
if (encodeType == EncodeType.HEX) {
return aes.encryptHex(value);
} else {
return aes.encryptBase64(value);
}
}
return value;
}
/**
* 解密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String decrypt(String value, EncodeType encodeType) throws Exception {
if (ObjectUtil.isNotNull(this.aes)) {
return this.aes.decryptStr(value);
}
return value;
}
}

View File

@ -0,0 +1,59 @@
package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.codec.Base64;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
/**
* Base64算法实现。不建议在生产环境使用
*
* @author 老马
* @date 2023-01-06 10:00
*/
public class Base64Encryptor extends AbstractEncryptor {
public Base64Encryptor(EncryptContext context) {
super(context);
}
/**
* 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/
@Override
public AlgorithmType algorithm() {
return AlgorithmType.BASE64;
}
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String encrypt(String value, EncodeType encodeType) throws Exception {
return Base64.encode(value);
}
/**
* 解密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String decrypt(String value, EncodeType encodeType) throws Exception {
return Base64.decodeStr(value);
}
}

View File

@ -0,0 +1,83 @@
package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
import com.ruoyi.common.utils.StringUtils;
/**
* RSA算法实现
*
* @author 老马
* @date 2023-01-06 09:37
*/
public class RsaEncryptor extends AbstractEncryptor {
private RSA rsa = null;
public RsaEncryptor(EncryptContext context) {
super(context);
String privateKey = context.getPrivateKey();
String publicKey = context.getPublicKey();
if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
throw new RuntimeException("rsa公私钥均需要提供公钥加密私钥解密。");
}
this.rsa = SecureUtil.rsa(Base64.decode(privateKey), Base64.decode(publicKey));
}
/**
* 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/
@Override
public AlgorithmType algorithm() {
return AlgorithmType.RSA;
}
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String encrypt(String value, EncodeType encodeType) throws Exception {
if (ObjectUtil.isNotNull(this.rsa)) {
if (encodeType == EncodeType.HEX) {
return rsa.encryptHex(value, KeyType.PublicKey);
} else {
return rsa.encryptBase64(value, KeyType.PublicKey);
}
}
return value;
}
/**
* 解密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String decrypt(String value, EncodeType encodeType) throws Exception {
if (ObjectUtil.isNotNull(this.rsa)) {
return this.rsa.decryptStr(value, KeyType.PrivateKey);
}
return value;
}
}

View File

@ -0,0 +1,85 @@
package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
import com.ruoyi.common.utils.StringUtils;
/**
* sm2算法实现
*
* @author 老马
* @date 2023-01-06 17:13
*/
public class Sm2Encryptor extends AbstractEncryptor {
private SM2 sm2 = null;
public Sm2Encryptor(EncryptContext context) {
super(context);
String privateKey = context.getPrivateKey();
String publicKey = context.getPublicKey();
if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
throw new RuntimeException("sm2公私钥均需要提供公钥加密私钥解密。");
}
this.sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey));
}
/**
* 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/
@Override
public AlgorithmType algorithm() {
return AlgorithmType.SM2;
}
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String encrypt(String value, EncodeType encodeType) throws Exception {
if (ObjectUtil.isNotNull(this.sm2)) {
if (encodeType == EncodeType.HEX) {
return sm2.encryptHex(value, KeyType.PublicKey);
} else {
return sm2.encryptBase64(value, KeyType.PublicKey);
}
}
return value;
}
/**
* 解密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String decrypt(String value, EncodeType encodeType) throws Exception {
if (ObjectUtil.isNotNull(this.sm2)) {
return this.sm2.decryptStr(value, KeyType.PrivateKey);
}
return value;
}
}

View File

@ -0,0 +1,87 @@
package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SM4;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
import java.nio.charset.StandardCharsets;
/**
* sm4算法实现
*
* @author 老马
* @date 2023-01-06 17:40
*/
public class Sm4Encryptor extends AbstractEncryptor {
private SM4 sm4 = null;
public Sm4Encryptor(EncryptContext context) {
super(context);
String password = context.getPassword();
if (StrUtil.isBlank(password)) {
throw new RuntimeException("sm4没有获得秘钥信息");
}
// sm4算法的秘钥要求是16位长度
if (16 != password.length()) {
throw new RuntimeException("sm4秘钥长度应该为16位实际为" + password.length() + "");
}
this.sm4 = SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8));
}
/**
* 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/
@Override
public AlgorithmType algorithm() {
return AlgorithmType.SM4;
}
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String encrypt(String value, EncodeType encodeType) throws Exception {
if (ObjectUtil.isNotNull(this.sm4)) {
if (encodeType == EncodeType.HEX) {
return sm4.encryptHex(value);
} else {
return sm4.encryptBase64(value);
}
}
return value;
}
/**
* 解密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/
@Override
public String decrypt(String value, EncodeType encodeType) throws Exception {
if (ObjectUtil.isNotNull(this.sm4)) {
return this.sm4.decryptStr(value);
}
return value;
}
}

View File

@ -0,0 +1,42 @@
package com.ruoyi.common.enums;
import com.ruoyi.common.encrypt.IEncryptor;
import com.ruoyi.common.encrypt.encryptor.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 算法名称
*
* @author 老马
*/
@Getter
@AllArgsConstructor
public enum AlgorithmType {
/**
* base64
*/
BASE64(Base64Encryptor.class),
/**
* aes
*/
AES(AesEncryptor.class),
/**
* rsa
*/
RSA(RsaEncryptor.class),
/**
* sm2
*/
SM2(Sm2Encryptor.class),
/**
* sm4
*/
SM4(Sm4Encryptor.class);
private final Class<? extends IEncryptor> clazz;
}

View File

@ -0,0 +1,20 @@
package com.ruoyi.common.enums;
/**
* 编码类型
*
* @author 老马
* @date 2023-01-11 11:39
*/
public enum EncodeType {
/**
* base64编码
*/
BASE64,
/**
* 16进制编码
*/
HEX;
}