diff --git a/pom.xml b/pom.xml index 8af16697e..8f687cca4 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,7 @@ 2.14.2 2.3.1 1.18.24 + 1.72 1.33 @@ -286,6 +287,13 @@ ${snakeyaml.version} + + + org.bouncycastle + bcprov-jdk15to18 + ${bouncycastle.version} + + com.ruoyi ruoyi-system diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 78d586bd9..2f496b023 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -180,6 +180,20 @@ mybatis-plus: # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件 where-strategy: NOT_NULL +# 数据加密 +mybatis-encryptor: + # 是否开启加密 + enable: false + # 默认加密算法 + algorithm: BASE64 + # 编码方式 BASE64/HEX。默认BASE64 + encode: BASE64 + # 安全秘钥 对称算法的秘钥 如:AES,SM4 + password: + # 公私钥 非对称算法的公私钥 如:SM2,RSA + publicKey: + privateKey: + # Swagger配置 swagger: info: diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 469235813..af49f5ffb 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -30,6 +30,7 @@ ruoyi-common-translation ruoyi-common-sensitive ruoyi-common-json + ruoyi-common-encrypt ruoyi-common diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index 739bfb6a9..72f28e462 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -145,6 +145,13 @@ ${revision} + + + com.ruoyi + ruoyi-common-encrypt + ${revision} + + diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml new file mode 100644 index 000000000..22aca400c --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -0,0 +1,43 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + ../pom.xml + + 4.0.0 + + ruoyi-common-encrypt + + + ruoyi-common-encrypt 数据加解密模块 + + + + + + com.ruoyi + ruoyi-common-core + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + + org.bouncycastle + bcprov-jdk15to18 + + + + cn.hutool + hutool-crypto + + + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/annotation/EncryptField.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/annotation/EncryptField.java new file mode 100644 index 000000000..f549a6a8e --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/annotation/EncryptField.java @@ -0,0 +1,44 @@ +package com.ruoyi.common.encrypt.annotation; + +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; + +import java.lang.annotation.*; + +/** + * 字段加密注解 + * + * @author 老马 + */ +@Documented +@Inherited +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface EncryptField { + + /** + * 加密算法 + */ + AlgorithmType algorithm() default AlgorithmType.DEFAULT; + + /** + * 秘钥。AES、SM4需要 + */ + String password() default ""; + + /** + * 公钥。RSA、SM2需要 + */ + String publicKey() default ""; + + /** + * 公钥。RSA、SM2需要 + */ + String privateKey() default ""; + + /** + * 编码方式。对加密算法为BASE64的不起作用 + */ + EncodeType encode() default EncodeType.DEFAULT; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/config/EncryptorAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/config/EncryptorAutoConfiguration.java new file mode 100644 index 000000000..d77226d0a --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/config/EncryptorAutoConfiguration.java @@ -0,0 +1,39 @@ +package com.ruoyi.common.encrypt.config; + +import com.ruoyi.common.encrypt.core.EncryptorManager; +import com.ruoyi.common.encrypt.interceptor.MybatisDecryptInterceptor; +import com.ruoyi.common.encrypt.interceptor.MybatisEncryptInterceptor; +import com.ruoyi.common.encrypt.properties.EncryptorProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; + +/** + * 加解密配置 + * + * @author 老马 + * @version 4.6.0 + */ +@AutoConfiguration +@ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true") +public class EncryptorAutoConfiguration { + + @Autowired + private EncryptorProperties properties; + + @Bean + public EncryptorManager encryptorManager() { + return new EncryptorManager(); + } + + @Bean + public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorManager encryptorManager) { + return new MybatisEncryptInterceptor(encryptorManager, properties); + } + + @Bean + public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) { + return new MybatisDecryptInterceptor(encryptorManager, properties); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptContext.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptContext.java new file mode 100644 index 000000000..ff3825488 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptContext.java @@ -0,0 +1,41 @@ +package com.ruoyi.common.encrypt.core; + +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; +import lombok.Data; + +/** + * 加密上下文 用于encryptor传递必要的参数。 + * + * @author 老马 + * @version 4.6.0 + */ +@Data +public class EncryptContext { + + /** + * 默认算法 + */ + private AlgorithmType algorithm; + + /** + * 安全秘钥 + */ + private String password; + + /** + * 公钥 + */ + private String publicKey; + + /** + * 私钥 + */ + private String privateKey; + + /** + * 编码方式,base64/hex + */ + private EncodeType encode; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptorManager.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptorManager.java new file mode 100644 index 000000000..d86eb71ad --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptorManager.java @@ -0,0 +1,94 @@ +package com.ruoyi.common.encrypt.core; + +import cn.hutool.core.util.ReflectUtil; +import com.ruoyi.common.encrypt.annotation.EncryptField; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 加密管理类 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +public class EncryptorManager { + + /** + * 缓存加密器 + */ + Map encryptorMap = new ConcurrentHashMap<>(); + + /** + * 类加密字段缓存 + */ + Map, Set> fieldCache = new ConcurrentHashMap<>(); + + /** + * 获取类加密字段缓存 + */ + public Set getFieldCache(Class sourceClazz) { + return fieldCache.computeIfAbsent(sourceClazz, clazz -> { + Field[] declaredFields = clazz.getDeclaredFields(); + Set fieldSet = Arrays.stream(declaredFields).filter(field -> + field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) + .collect(Collectors.toSet()); + for (Field field : fieldSet) { + field.setAccessible(true); + } + return fieldSet; + }); + } + + /** + * 注册加密执行者到缓存 + * + * @param encryptContext 加密执行者需要的相关配置参数 + */ + public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) { + if (encryptorMap.containsKey(encryptContext)) { + return encryptorMap.get(encryptContext); + } + IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext); + encryptorMap.put(encryptContext, encryptor); + return encryptor; + } + + /** + * 移除缓存中的加密执行者 + * + * @param encryptContext 加密执行者需要的相关配置参数 + */ + public void removeEncryptor(EncryptContext encryptContext) { + this.encryptorMap.remove(encryptContext); + } + + /** + * 根据配置进行加密。会进行本地缓存对应的算法和对应的秘钥信息。 + * + * @param value 待加密的值 + * @param encryptContext 加密相关的配置信息 + */ + public String encrypt(String value, EncryptContext encryptContext) { + IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); + return encryptor.encrypt(value, encryptContext.getEncode()); + } + + /** + * 根据配置进行解密 + * + * @param value 待解密的值 + * @param encryptContext 加密相关的配置信息 + */ + public String decrypt(String value, EncryptContext encryptContext) { + IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); + return encryptor.decrypt(value); + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/IEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/IEncryptor.java new file mode 100644 index 000000000..d9642c0d1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/IEncryptor.java @@ -0,0 +1,35 @@ +package com.ruoyi.common.encrypt.core; + +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; + +/** + * 加解者 + * + * @author 老马 + * @version 4.6.0 + */ +public interface IEncryptor { + + /** + * 获得当前算法 + */ + AlgorithmType algorithm(); + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + * @return 加密后的字符串 + */ + String encrypt(String value, EncodeType encodeType); + + /** + * 解密 + * + * @param value 待加密字符串 + * @return 解密后的字符串 + */ + String decrypt(String value); +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AbstractEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AbstractEncryptor.java new file mode 100644 index 000000000..b068ce77a --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AbstractEncryptor.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.encrypt.core.encryptor; + +import com.ruoyi.common.encrypt.core.EncryptContext; +import com.ruoyi.common.encrypt.core.IEncryptor; + +/** + * 所有加密执行者的基类 + * + * @author 老马 + * @version 4.6.0 + */ +public abstract class AbstractEncryptor implements IEncryptor { + + public AbstractEncryptor(EncryptContext context) { + // 用户配置校验与配置注入 + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java new file mode 100644 index 000000000..ea89d2cb7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java @@ -0,0 +1,69 @@ +package com.ruoyi.common.encrypt.core.encryptor; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import com.ruoyi.common.encrypt.core.EncryptContext; +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; + +import java.nio.charset.StandardCharsets; + +/** + * AES算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class AesEncryptor extends AbstractEncryptor { + + private final AES aes; + + public AesEncryptor(EncryptContext context) { + super(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)); + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.AES; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return aes.encryptHex(value); + } else { + return aes.encryptBase64(value); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return this.aes.decryptStr(value); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java new file mode 100644 index 000000000..70f3e0026 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java @@ -0,0 +1,48 @@ +package com.ruoyi.common.encrypt.core.encryptor; + +import cn.hutool.core.codec.Base64; +import com.ruoyi.common.encrypt.core.EncryptContext; +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; + +/** + * Base64算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Base64Encryptor extends AbstractEncryptor { + + public Base64Encryptor(EncryptContext context) { + super(context); + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.BASE64; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + return Base64.encode(value); + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return Base64.decodeStr(value); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java new file mode 100644 index 000000000..bd7774ec2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java @@ -0,0 +1,65 @@ +package com.ruoyi.common.encrypt.core.encryptor; + +import cn.hutool.core.codec.Base64; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.encrypt.core.EncryptContext; +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; + + +/** + * RSA算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class RsaEncryptor extends AbstractEncryptor { + + private final RSA rsa; + + public RsaEncryptor(EncryptContext context) { + super(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)); + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.RSA; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + 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 待加密字符串 + */ + @Override + public String decrypt(String value) { + return this.rsa.decryptStr(value, KeyType.PrivateKey); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java new file mode 100644 index 000000000..1e0bb9f17 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java @@ -0,0 +1,64 @@ +package com.ruoyi.common.encrypt.core.encryptor; + +import cn.hutool.core.codec.Base64; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.SM2; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.encrypt.core.EncryptContext; +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; + +/** + * sm2算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Sm2Encryptor extends AbstractEncryptor { + + private final SM2 sm2; + + public Sm2Encryptor(EncryptContext context) { + super(context); + String privateKey = context.getPrivateKey(); + String publicKey = context.getPublicKey(); + if (StringUtils.isAnyEmpty(privateKey, publicKey)) { + throw new IllegalArgumentException("SM2公私钥均需要提供,公钥加密,私钥解密。"); + } + this.sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey)); + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.SM2; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return sm2.encryptHex(value, KeyType.PublicKey); + } else { + return sm2.encryptBase64(value, KeyType.PublicKey); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return this.sm2.decryptStr(value, KeyType.PrivateKey); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java new file mode 100644 index 000000000..b15050388 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java @@ -0,0 +1,67 @@ +package com.ruoyi.common.encrypt.core.encryptor; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.symmetric.SM4; +import com.ruoyi.common.encrypt.core.EncryptContext; +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; + +import java.nio.charset.StandardCharsets; + +/** + * sm4算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Sm4Encryptor extends AbstractEncryptor { + + private final SM4 sm4; + + public Sm4Encryptor(EncryptContext context) { + super(context); + String password = context.getPassword(); + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4没有获得秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + if (16 != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度应该为16位,实际为" + password.length() + "位"); + } + this.sm4 = SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)); + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.SM4; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return sm4.encryptHex(value); + } else { + return sm4.encryptBase64(value); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return this.sm4.decryptStr(value); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/AlgorithmType.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/AlgorithmType.java new file mode 100644 index 000000000..ff02ecb75 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/AlgorithmType.java @@ -0,0 +1,48 @@ +package com.ruoyi.common.encrypt.enumd; + +import com.ruoyi.common.encrypt.core.encryptor.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 算法名称 + * + * @author 老马 + * @version 4.6.0 + */ +@Getter +@AllArgsConstructor +public enum AlgorithmType { + + /** + * 默认走yml配置 + */ + DEFAULT(null), + + /** + * base64 + */ + BASE64(Base64Encryptor.class), + + /** + * aes + */ + AES(AesEncryptor.class), + + /** + * rsa + */ + RSA(RsaEncryptor.class), + + /** + * sm2 + */ + SM2(Sm2Encryptor.class), + + /** + * sm4 + */ + SM4(Sm4Encryptor.class); + + private final Class clazz; +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/EncodeType.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/EncodeType.java new file mode 100644 index 000000000..f8d54999a --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/EncodeType.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.encrypt.enumd; + +/** + * 编码类型 + * + * @author 老马 + * @version 4.6.0 + */ +public enum EncodeType { + + /** + * 默认使用yml配置 + */ + DEFAULT, + + /** + * base64编码 + */ + BASE64, + + /** + * 16进制编码 + */ + HEX; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java new file mode 100644 index 000000000..925d4e419 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java @@ -0,0 +1,108 @@ +package com.ruoyi.common.encrypt.interceptor; + +import cn.hutool.core.collection.CollectionUtil; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.encrypt.annotation.EncryptField; +import com.ruoyi.common.encrypt.core.EncryptContext; +import com.ruoyi.common.encrypt.core.EncryptorManager; +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; +import com.ruoyi.common.encrypt.properties.EncryptorProperties; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.resultset.ResultSetHandler; +import org.apache.ibatis.plugin.*; + +import java.lang.reflect.Field; +import java.sql.Statement; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * 出参解密拦截器 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +@Intercepts({@Signature( + type = ResultSetHandler.class, + method = "handleResultSets", + args = {Statement.class}) +}) +@AllArgsConstructor +public class MybatisDecryptInterceptor implements Interceptor { + + private final EncryptorManager encryptorManager; + private final EncryptorProperties defaultProperties; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + // 获取执行mysql执行结果 + Object result = invocation.proceed(); + if (result == null) { + return null; + } + decryptHandler(result); + return result; + } + + /** + * 解密对象 + * + * @param sourceObject 待加密对象 + */ + private void decryptHandler(Object sourceObject) { + if (sourceObject instanceof Map) { + ((Map) sourceObject).values().forEach(this::decryptHandler); + return; + } + if (sourceObject instanceof List) { + // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 + Object firstItem = ((List) sourceObject).get(0); + if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { + return; + } + ((List) sourceObject).forEach(this::decryptHandler); + return; + } + Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + try { + for (Field field : fields) { + field.set(sourceObject, this.decryptField(String.valueOf(field.get(sourceObject)), field)); + } + } catch (Exception e) { + log.error("处理解密字段时出错", e); + } + } + + /** + * 字段值进行加密。通过字段的批注注册新的加密算法 + * + * @param value 待加密的值 + * @param field 待加密字段 + * @return 加密后结果 + */ + private String decryptField(String value, Field field) { + EncryptField encryptField = field.getAnnotation(EncryptField.class); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); + encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); + encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); + encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); + encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); + return this.encryptorManager.decrypt(value, encryptContext); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java new file mode 100644 index 000000000..97fc0a450 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java @@ -0,0 +1,115 @@ +package com.ruoyi.common.encrypt.interceptor; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.encrypt.annotation.EncryptField; +import com.ruoyi.common.encrypt.core.EncryptContext; +import com.ruoyi.common.encrypt.core.EncryptorManager; +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; +import com.ruoyi.common.encrypt.properties.EncryptorProperties; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.parameter.ParameterHandler; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * 入参加密拦截器 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +@Intercepts({@Signature( + type = ParameterHandler.class, + method = "setParameters", + args = {PreparedStatement.class}) +}) +@AllArgsConstructor +public class MybatisEncryptInterceptor implements Interceptor { + + private final EncryptorManager encryptorManager; + private final EncryptorProperties defaultProperties; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + return invocation; + } + + @Override + public Object plugin(Object target) { + if (target instanceof ParameterHandler) { + // 进行加密操作 + ParameterHandler parameterHandler = (ParameterHandler) target; + Object parameterObject = parameterHandler.getParameterObject(); + if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) { + this.encryptHandler(parameterObject); + } + } + return target; + } + + /** + * 加密对象 + * + * @param sourceObject 待加密对象 + */ + @SuppressWarnings("unchecked cast") + private void encryptHandler(Object sourceObject) { + if (sourceObject instanceof Map) { + ((Map) sourceObject).values().forEach(this::encryptHandler); + return; + } + if (sourceObject instanceof List) { + // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 + Object firstItem = ((List) sourceObject).get(0); + if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { + return; + } + ((List) sourceObject).forEach(this::encryptHandler); + return; + } + Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + try { + for (Field field : fields) { + field.set(sourceObject, this.encryptField(String.valueOf(field.get(sourceObject)), field)); + } + } catch (Exception e) { + log.error("处理加密字段时出错", e); + } + } + + /** + * 字段值进行加密。通过字段的批注注册新的加密算法 + * + * @param value 待加密的值 + * @param field 待加密字段 + * @return 加密后结果 + */ + private String encryptField(String value, Field field) { + EncryptField encryptField = field.getAnnotation(EncryptField.class); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); + encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); + encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); + encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); + encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); + return this.encryptorManager.encrypt(value, encryptContext); + } + + + @Override + public void setProperties(Properties properties) { + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/properties/EncryptorProperties.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/properties/EncryptorProperties.java new file mode 100644 index 000000000..bd8c28d0e --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/properties/EncryptorProperties.java @@ -0,0 +1,50 @@ +package com.ruoyi.common.encrypt.properties; + +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import com.ruoyi.common.encrypt.enumd.EncodeType; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 加解密属性配置类 + * + * @author 老马 + * @version 4.6.0 + */ +@Data +@Component +@ConfigurationProperties(prefix = "mybatis-encryptor") +public class EncryptorProperties { + + /** + * 过滤开关 + */ + private Boolean enable; + + /** + * 默认算法 + */ + private AlgorithmType algorithm; + + /** + * 安全秘钥 + */ + private String password; + + /** + * 公钥 + */ + private String publicKey; + + /** + * 私钥 + */ + private String privateKey; + + /** + * 编码方式,base64/hex + */ + private EncodeType encode; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..e1063e2bc --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.ruoyi.common.encrypt.config.EncryptorAutoConfiguration diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/OssUrlTranslationImpl.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/OssUrlTranslationImpl.java index 00a3f3842..02eff57f3 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/OssUrlTranslationImpl.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/OssUrlTranslationImpl.java @@ -22,6 +22,8 @@ public class OssUrlTranslationImpl implements TranslationInterface { public String translation(Object key, String other) { if (key instanceof String ids) { return ossService.selectUrlByIds(ids); + } else if (key instanceof Long id) { + return ossService.selectUrlByIds(id.toString()); } return null; } diff --git a/ruoyi-modules/ruoyi-demo/pom.xml b/ruoyi-modules/ruoyi-demo/pom.xml index 7f8eac032..cd7bdb134 100644 --- a/ruoyi-modules/ruoyi-demo/pom.xml +++ b/ruoyi-modules/ruoyi-demo/pom.xml @@ -83,6 +83,11 @@ ruoyi-common-sensitive + + com.ruoyi + ruoyi-common-encrypt + + diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestEncryptController.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestEncryptController.java new file mode 100644 index 000000000..6abe4e184 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestEncryptController.java @@ -0,0 +1,55 @@ +package com.ruoyi.demo.controller; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.demo.domain.TestDemoEncrypt; +import com.ruoyi.demo.mapper.TestDemoEncryptMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + + +/** + * 测试数据库加解密功能 + * + * @author Lion Li + */ +@Validated +@RestController +@RequestMapping("/demo/encrypt") +public class TestEncryptController { + + @Autowired + private TestDemoEncryptMapper mapper; + @Value("${mybatis-encryptor.enable}") + private Boolean encryptEnable; + + /** + * 测试数据库加解密 + * + * @param key 测试key + * @param value 测试value + */ + @GetMapping() + public R> test(String key, String value) { + if (!encryptEnable) { + throw new RuntimeException("加密功能未开启!"); + } + Map map = new HashMap<>(2); + TestDemoEncrypt demo = new TestDemoEncrypt(); + demo.setTestKey(key); + demo.setValue(value); + mapper.insert(demo); + map.put("加密", demo); + TestDemoEncrypt testDemo = mapper.selectById(demo.getId()); + map.put("解密", testDemo); + return R.ok(map); + } + + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemoEncrypt.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemoEncrypt.java new file mode 100644 index 000000000..0214e8d58 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemoEncrypt.java @@ -0,0 +1,29 @@ +package com.ruoyi.demo.domain; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.ruoyi.common.encrypt.annotation.EncryptField; +import com.ruoyi.common.encrypt.enumd.AlgorithmType; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_demo") +public class TestDemoEncrypt extends TestDemo { + + /** + * key键 + */ + // @EncryptField(algorithm=AlgorithmType.SM2, privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgZSlOvw8FBiH+aFJWLYZP/VRjg9wjfRarTkGBZd/T3N+gCgYIKoEcz1UBgi2hRANCAAR5DGuQwJqkxnbCsP+iPSDoHWIF4RwcR5EsSvT8QPxO1wRkR2IhCkzvRb32x2CUgJFdvoqVqfApFDPZzShqzBwX", publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEeQxrkMCapMZ2wrD/oj0g6B1iBeEcHEeRLEr0/ED8TtcEZEdiIQpM70W99sdglICRXb6KlanwKRQz2c0oaswcFw==") + @EncryptField(algorithm = AlgorithmType.RSA, privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANBBEeueWlXlkkj2+WY5l+IWe42d8b5K28g+G/CFKC/yYAEHtqGlCsBOrb+YBkG9mPzmuYA/n9k0NFIc8E8yY5vZQaroyFBrTTWEzG9RY2f7Y3svVyybs6jpXSUs4xff8abo7wL1Y/wUaeatTViamxYnyTvdTmLm3d+JjRij68rxAgMBAAECgYAB0TnhXraSopwIVRfmboea1b0upl+BUdTJcmci412UjrKr5aE695ZLPkXbFXijVu7HJlyyv94NVUdaMACV7Ku/S2RuNB70M7YJm8rAjHFC3/i2ZeIM60h1Ziy4QKv0XM3pRATlDCDNhC1WUrtQCQSgU8kcp6eUUppruOqDzcY04QJBAPm9+sBP9CwDRgy3e5+V8aZtJkwDstb0lVVV/KY890cydVxiCwvX3fqVnxKMlb+x0YtH0sb9v+71xvK2lGobaRECQQDVePU6r/cCEfpc+nkWF6osAH1f8Mux3rYv2DoBGvaPzV2BGfsLed4neRfCwWNCKvGPCdW+L0xMJg8+RwaoBUPhAkAT5kViqXxFPYWJYd1h2+rDXhMdH3ZSlm6HvDBDdrwlWinr0Iwcx3iSjPV93uHXwm118aUj4fg3LDJMCKxOwBxhAkByrQXfvwOMYygBprRBf/j0plazoWFrbd6lGR0f1uI5IfNnFRPdeFw1DEINZ2Hw+6zEUF44SqRMC+4IYJNc02dBAkBCgy7RvfyV/A7N6kKXxTHauY0v6XwSSvpeKtRJkbIcRWOdIYvaHO9L7cklj3vIEdwjSUp9K4VTBYYlmAz1xh03", publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQQRHrnlpV5ZJI9vlmOZfiFnuNnfG+StvIPhvwhSgv8mABB7ahpQrATq2/mAZBvZj85rmAP5/ZNDRSHPBPMmOb2UGq6MhQa001hMxvUWNn+2N7L1csm7Oo6V0lLOMX3/Gm6O8C9WP8FGnmrU1YmpsWJ8k73U5i5t3fiY0Yo+vK8QIDAQAB") + private String testKey; + + /** + * 值 + */ + // @EncryptField // 什么也不写走默认yml配置 + // @EncryptField(algorithm = AlgorithmType.SM4, password = "10rfylhtccpuyke5") + @EncryptField(algorithm = AlgorithmType.AES, password = "10rfylhtccpuyke5") + private String value; + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoEncryptMapper.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoEncryptMapper.java new file mode 100644 index 000000000..cef30afb1 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoEncryptMapper.java @@ -0,0 +1,13 @@ +package com.ruoyi.demo.mapper; + +import com.ruoyi.common.mybatis.core.mapper.BaseMapperPlus; +import com.ruoyi.demo.domain.TestDemoEncrypt; + +/** + * 测试加密功能 + * + * @author Lion Li + */ +public interface TestDemoEncryptMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysProfileController.java index 48c78d307..5e84c07d2 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysProfileController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysProfileController.java @@ -1,6 +1,7 @@ package com.ruoyi.system.controller.system; import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.io.FileUtil; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.domain.R; @@ -11,6 +12,7 @@ import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.satoken.utils.LoginHelper; import com.ruoyi.common.web.core.BaseController; import com.ruoyi.system.domain.bo.SysUserBo; +import com.ruoyi.system.domain.bo.SysUserProfileBo; import com.ruoyi.system.domain.vo.AvatarVo; import com.ruoyi.system.domain.vo.ProfileVo; import com.ruoyi.system.domain.vo.SysOssVo; @@ -57,7 +59,8 @@ public class SysProfileController extends BaseController { */ @Log(title = "个人信息", businessType = BusinessType.UPDATE) @PutMapping - public R updateProfile(@RequestBody SysUserBo user) { + public R updateProfile(@RequestBody SysUserProfileBo profile) { + SysUserBo user = BeanUtil.copyProperties(profile, SysUserBo.class); if (StringUtils.isNotEmpty(user.getPhonenumber()) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); @@ -67,10 +70,6 @@ public class SysProfileController extends BaseController { return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); } user.setUserId(LoginHelper.getUserId()); - user.setUserName(null); - user.setPassword(null); - user.setAvatar(null); - user.setDeptId(null); if (userService.updateUserProfile(user) > 0) { return R.ok(); } @@ -117,7 +116,7 @@ public class SysProfileController extends BaseController { } SysOssVo oss = iSysOssService.upload(avatarfile); String avatar = oss.getUrl(); - if (userService.updateUserAvatar(LoginHelper.getUsername(), avatar)) { + if (userService.updateUserAvatar(LoginHelper.getUsername(), oss.getOssId())) { AvatarVo avatarVo = new AvatarVo(); avatarVo.setImgUrl(avatar); return R.ok(avatarVo); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java index 42cfb96ec..0338b376d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java @@ -65,7 +65,7 @@ public class SysUser extends BaseEntity { /** * 用户头像 */ - private String avatar; + private Long avatar; /** * 密码 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java index 66732141c..b0e49ffe1 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java @@ -13,22 +13,31 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) public class SysOssBo extends BaseEntity { + /** + * ossId + */ + private Long ossId; + /** * 文件名 */ private String fileName; + /** * 原名 */ private String originalName; + /** * 文件后缀名 */ private String fileSuffix; + /** * URL地址 */ private String url; + /** * 服务商 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java index 02b1804b2..cd9dd4007 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java @@ -77,7 +77,7 @@ public class SysUserBo extends BaseEntity { /** * 头像地址 */ - private String avatar; + private Long avatar; /** * 密码 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserProfileBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserProfileBo.java new file mode 100644 index 000000000..bfa78624b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserProfileBo.java @@ -0,0 +1,55 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.xss.Xss; +import com.ruoyi.common.mybatis.core.domain.BaseEntity; +import com.ruoyi.common.sensitive.annotation.Sensitive; +import com.ruoyi.common.sensitive.core.SensitiveStrategy; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 个人信息业务处理 + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SysUserProfileBo extends BaseEntity { + + /** + * 用户ID + */ + private Long userId; + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户邮箱 + */ + @Sensitive(strategy = SensitiveStrategy.EMAIL) + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + @Sensitive(strategy = SensitiveStrategy.PHONE) + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java index e85d3835d..90849b1d9 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java @@ -1,6 +1,8 @@ package com.ruoyi.system.domain.vo; import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.translation.annotation.Translation; +import com.ruoyi.common.translation.constant.TransConstant; import lombok.Data; import java.io.Serial; @@ -63,7 +65,8 @@ public class SysUserVo implements Serializable { /** * 头像地址 */ - private String avatar; + @Translation(type = TransConstant.OSS_ID_TO_URL) + private Long avatar; /** * 密码 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index 49bb38e37..dd9bccc48 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -174,7 +174,7 @@ public interface ISysUserService { * @param avatar 头像地址 * @return 结果 */ - boolean updateUserAvatar(String userName, String avatar); + boolean updateUserAvatar(String userName, Long avatar); /** * 重置用户密码 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 9c82ff6dd..ee36fe536 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -373,7 +373,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService { * @return 结果 */ @Override - public boolean updateUserAvatar(String userName, String avatar) { + public boolean updateUserAvatar(String userName, Long avatar) { return baseMapper.update(null, new LambdaUpdateWrapper() .set(SysUser::getAvatar, avatar) diff --git a/script/sql/oracle/oracle_ry_vue_5.X.sql b/script/sql/oracle/oracle_ry_vue_5.X.sql index f2f93dfa1..055894811 100644 --- a/script/sql/oracle/oracle_ry_vue_5.X.sql +++ b/script/sql/oracle/oracle_ry_vue_5.X.sql @@ -155,7 +155,7 @@ create table sys_user ( email varchar2(50) default '', phonenumber varchar2(11) default '', sex char(1) default '0', - avatar varchar2(100) default '', + avatar number(20) default null, password varchar2(100) default '', status char(1) default '0', del_flag char(1) default '0', @@ -197,8 +197,8 @@ comment on column sys_user.remark is '备注'; -- ---------------------------- -- 初始化-用户信息表数据 -- ---------------------------- -insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '管理员'); -insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '测试员'); +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '管理员'); +insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '测试员'); -- ---------------------------- diff --git a/script/sql/postgres/postgres_ry_vue_5.X.sql b/script/sql/postgres/postgres_ry_vue_5.X.sql index ab3b78a40..cc622e152 100644 --- a/script/sql/postgres/postgres_ry_vue_5.X.sql +++ b/script/sql/postgres/postgres_ry_vue_5.X.sql @@ -162,7 +162,7 @@ create table if not exists sys_user email varchar(50) default ''::varchar, phonenumber varchar(11) default ''::varchar, sex char default '0'::bpchar, - avatar varchar(100) default ''::varchar, + avatar int8, password varchar(100) default ''::varchar, status char default '0'::bpchar, del_flag char default '0'::bpchar, @@ -204,8 +204,8 @@ comment on column sys_user.remark is '备注'; -- 初始化-用户信息表数据 -- ---------------------------- -insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '管理员'); -insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '测试员'); +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '管理员'); +insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '测试员'); -- ---------------------------- diff --git a/script/sql/ry_vue_5.X.sql b/script/sql/ry_vue_5.X.sql index 5cc966b77..b5528439f 100644 --- a/script/sql/ry_vue_5.X.sql +++ b/script/sql/ry_vue_5.X.sql @@ -109,7 +109,7 @@ create table sys_user ( email varchar(50) default '' comment '用户邮箱', phonenumber varchar(11) default '' comment '手机号码', sex char(1) default '0' comment '用户性别(0男 1女 2未知)', - avatar varchar(100) default '' comment '头像地址', + avatar bigint(20) comment '头像地址', password varchar(100) default '' comment '密码', status char(1) default '0' comment '帐号状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', @@ -127,8 +127,8 @@ create table sys_user ( -- ---------------------------- -- 初始化-用户信息表数据 -- ---------------------------- -insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '管理员'); -insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '测试员'); +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '管理员'); +insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '测试员'); -- ---------------------------- diff --git a/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql index 3eadba963..fe7474666 100644 --- a/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql +++ b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql @@ -2273,7 +2273,7 @@ CREATE TABLE [sys_user] [email] nvarchar(50) DEFAULT '' NULL, [phonenumber] nvarchar(11) DEFAULT '' NULL, [sex] nchar(1) DEFAULT ('0') NULL, - [avatar] nvarchar(100) DEFAULT '' NULL, + [avatar] bigint NULL, [password] nvarchar(100) DEFAULT '' NULL, [status] nchar(1) DEFAULT ('0') NULL, [del_flag] nchar(1) DEFAULT ('0') NULL, @@ -2424,9 +2424,9 @@ EXEC sys.sp_addextendedproperty 'TABLE', N'sys_user' GO -INSERT [sys_user] ([user_id], [tenant_id], [dept_id], [user_name], [nick_name], [user_type], [email], [phonenumber], [sex], [avatar], [password], [status], [del_flag], [login_ip], [login_date], [create_dept], [create_by], [create_time], [update_by], [update_time], [remark]) VALUES (1, 103, N'000000', N'admin', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', N'', N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'管理员') +INSERT [sys_user] ([user_id], [tenant_id], [dept_id], [user_name], [nick_name], [user_type], [email], [phonenumber], [sex], [avatar], [password], [status], [del_flag], [login_ip], [login_date], [create_dept], [create_by], [create_time], [update_by], [update_time], [remark]) VALUES (1, 103, N'000000', N'admin', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'管理员') GO -INSERT [sys_user] ([user_id], [tenant_id], [dept_id], [user_name], [nick_name], [user_type], [email], [phonenumber], [sex], [avatar], [password], [status], [del_flag], [login_ip], [login_date], [create_dept], [create_by], [create_time], [update_by], [update_time], [remark]) VALUES (2, 105, N'000000', N'lionli', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@qq.com', N'15666666666', N'1', N'', N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'测试员') +INSERT [sys_user] ([user_id], [tenant_id], [dept_id], [user_name], [nick_name], [user_type], [email], [phonenumber], [sex], [avatar], [password], [status], [del_flag], [login_ip], [login_date], [create_dept], [create_by], [create_time], [update_by], [update_time], [remark]) VALUES (2, 105, N'000000', N'lionli', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@qq.com', N'15666666666', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'测试员') GO CREATE TABLE [sys_user_post]