mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-11-04 09:01:40 +08:00 
			
		
		
		
	feat(security/crypto): 新增安全模块-加密,支持 MyBatis ORM 框架字段加密
This commit is contained in:
		@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.annotation;
 | 
			
		||||
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.enums.Algorithm;
 | 
			
		||||
 | 
			
		||||
import java.lang.annotation.ElementType;
 | 
			
		||||
import java.lang.annotation.Retention;
 | 
			
		||||
import java.lang.annotation.RetentionPolicy;
 | 
			
		||||
import java.lang.annotation.Target;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 字段加/解密注解
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
@Target(ElementType.FIELD)
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
public @interface FieldEncrypt {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 加密/解密算法
 | 
			
		||||
     */
 | 
			
		||||
    Algorithm value() default Algorithm.AES;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 加密/解密处理器
 | 
			
		||||
     * <p>
 | 
			
		||||
     * 优先级高于加密/解密算法
 | 
			
		||||
     * </p>
 | 
			
		||||
     */
 | 
			
		||||
    Class<? extends IEncryptor> encryptor() default IEncryptor.class;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 对称加密算法密钥
 | 
			
		||||
     */
 | 
			
		||||
    String password() default "";
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,71 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.autoconfigure;
 | 
			
		||||
 | 
			
		||||
import jakarta.annotation.PostConstruct;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 | 
			
		||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import top.charles7c.continew.starter.core.constant.PropertiesConstants;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.core.MyBatisDecryptInterceptor;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.core.MyBatisEncryptInterceptor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 加/解密自动配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
@AutoConfiguration
 | 
			
		||||
@EnableConfigurationProperties(CryptoProperties.class)
 | 
			
		||||
@ConditionalOnProperty(prefix = PropertiesConstants.CRYPTO, name = PropertiesConstants.ENABLED, havingValue = "true", matchIfMissing = true)
 | 
			
		||||
public class CryptoAutoConfiguration {
 | 
			
		||||
 | 
			
		||||
    private static final Logger log = LoggerFactory.getLogger(CryptoAutoConfiguration.class);
 | 
			
		||||
    private final CryptoProperties properties;
 | 
			
		||||
 | 
			
		||||
    public CryptoAutoConfiguration(CryptoProperties properties) {
 | 
			
		||||
        this.properties = properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * MyBatis 加密拦截器配置
 | 
			
		||||
     */
 | 
			
		||||
    @Bean
 | 
			
		||||
    @ConditionalOnMissingBean(MyBatisEncryptInterceptor.class)
 | 
			
		||||
    public MyBatisEncryptInterceptor myBatisEncryptInterceptor() {
 | 
			
		||||
        return new MyBatisEncryptInterceptor(properties);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * MyBatis 解密拦截器配置
 | 
			
		||||
     */
 | 
			
		||||
    @Bean
 | 
			
		||||
    @ConditionalOnMissingBean(MyBatisDecryptInterceptor.class)
 | 
			
		||||
    public MyBatisDecryptInterceptor myBatisDecryptInterceptor() {
 | 
			
		||||
        return new MyBatisDecryptInterceptor(properties);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostConstruct
 | 
			
		||||
    public void postConstruct() {
 | 
			
		||||
        log.debug("[ContiNew Starter] - Auto Configuration 'Security-Crypto' completed initialization.");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.autoconfigure;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.context.properties.ConfigurationProperties;
 | 
			
		||||
import top.charles7c.continew.starter.core.constant.PropertiesConstants;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 加/解密配置属性
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
@ConfigurationProperties(PropertiesConstants.CRYPTO)
 | 
			
		||||
public class CryptoProperties {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用加/解密配置
 | 
			
		||||
     */
 | 
			
		||||
    private boolean enabled = true;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 对称加密算法密钥
 | 
			
		||||
     */
 | 
			
		||||
    private String password;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 非对称加密算法公钥
 | 
			
		||||
     */
 | 
			
		||||
    private String publicKey;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 非对称加密算法私钥
 | 
			
		||||
     */
 | 
			
		||||
    private String privateKey;
 | 
			
		||||
 | 
			
		||||
    public boolean isEnabled() {
 | 
			
		||||
        return enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setEnabled(boolean enabled) {
 | 
			
		||||
        this.enabled = enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getPassword() {
 | 
			
		||||
        return password;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPassword(String password) {
 | 
			
		||||
        this.password = password;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getPublicKey() {
 | 
			
		||||
        return publicKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPublicKey(String publicKey) {
 | 
			
		||||
        this.publicKey = publicKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getPrivateKey() {
 | 
			
		||||
        return privateKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPrivateKey(String privateKey) {
 | 
			
		||||
        this.privateKey = privateKey;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,73 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.core;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.ReflectUtil;
 | 
			
		||||
import cn.hutool.extra.spring.SpringUtil;
 | 
			
		||||
import org.apache.ibatis.plugin.*;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.annotation.FieldEncrypt;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.enums.Algorithm;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 字段解密拦截器
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractMyBatisInterceptor implements Interceptor {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取所有字符串类型、需要加/解密的、有值字段
 | 
			
		||||
     *
 | 
			
		||||
     * @param obj 对象
 | 
			
		||||
     * @return 字段列表
 | 
			
		||||
     */
 | 
			
		||||
    public List<Field> getEncryptFields(Object obj) {
 | 
			
		||||
        if (null == obj) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
        return Arrays.stream(ReflectUtil.getFields(obj.getClass()))
 | 
			
		||||
            .filter(field -> String.class.equals(field.getType()))
 | 
			
		||||
            .filter(field -> null != field.getAnnotation(FieldEncrypt.class))
 | 
			
		||||
            .filter(field -> null != ReflectUtil.getFieldValue(obj, field))
 | 
			
		||||
            .toList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取字段加/解密处理器
 | 
			
		||||
     *
 | 
			
		||||
     * @param field 字段
 | 
			
		||||
     * @return 加/解密处理器
 | 
			
		||||
     */
 | 
			
		||||
    public IEncryptor getEncryptor(Field field) {
 | 
			
		||||
        FieldEncrypt fieldEncrypt = field.getAnnotation(FieldEncrypt.class);
 | 
			
		||||
        Class<? extends IEncryptor> encryptorClass = fieldEncrypt.encryptor();
 | 
			
		||||
        // 使用预定义加/解密处理器
 | 
			
		||||
        if (encryptorClass == IEncryptor.class) {
 | 
			
		||||
            Algorithm algorithm = fieldEncrypt.value();
 | 
			
		||||
            return ReflectUtil.newInstance(algorithm.getEncryptor());
 | 
			
		||||
        }
 | 
			
		||||
        // 使用自定义加/解密处理器
 | 
			
		||||
        return SpringUtil.getBean(encryptorClass);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,77 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.core;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.hutool.core.util.ReflectUtil;
 | 
			
		||||
import org.apache.ibatis.executor.resultset.ResultSetHandler;
 | 
			
		||||
import org.apache.ibatis.plugin.*;
 | 
			
		||||
import org.apache.ibatis.type.SimpleTypeRegistry;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.annotation.FieldEncrypt;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.autoconfigure.CryptoProperties;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.sql.Statement;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 字段解密拦截器
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
 | 
			
		||||
public class MyBatisDecryptInterceptor extends AbstractMyBatisInterceptor {
 | 
			
		||||
 | 
			
		||||
    private CryptoProperties properties;
 | 
			
		||||
 | 
			
		||||
    public MyBatisDecryptInterceptor(CryptoProperties properties) {
 | 
			
		||||
        this.properties = properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MyBatisDecryptInterceptor() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Object intercept(Invocation invocation) throws Throwable {
 | 
			
		||||
        Object obj = invocation.proceed();
 | 
			
		||||
        if (null == obj || !(invocation.getTarget() instanceof ResultSetHandler)) {
 | 
			
		||||
            return obj;
 | 
			
		||||
        }
 | 
			
		||||
        List<?> resultList = (List<?>)obj;
 | 
			
		||||
        for (Object result : resultList) {
 | 
			
		||||
            // String、Integer、Long 等简单类型对象无需处理
 | 
			
		||||
            if (SimpleTypeRegistry.isSimpleType(result.getClass())) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            // 获取所有字符串类型、需要解密的、有值字段
 | 
			
		||||
            List<Field> fieldList = super.getEncryptFields(result);
 | 
			
		||||
            // 解密处理
 | 
			
		||||
            for (Field field : fieldList) {
 | 
			
		||||
                IEncryptor encryptor = super.getEncryptor(field);
 | 
			
		||||
                Object fieldValue = ReflectUtil.getFieldValue(result, field);
 | 
			
		||||
                // 优先获取自定义对称加密算法密钥,获取不到时再获取全局配置
 | 
			
		||||
                String password = ObjectUtil.defaultIfBlank(field.getAnnotation(FieldEncrypt.class)
 | 
			
		||||
                    .password(), properties.getPassword());
 | 
			
		||||
                String ciphertext = encryptor.decrypt(fieldValue.toString(), password, properties.getPrivateKey());
 | 
			
		||||
                ReflectUtil.setFieldValue(result, field, ciphertext);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return resultList;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.core;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.hutool.core.util.ReflectUtil;
 | 
			
		||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
 | 
			
		||||
import org.apache.ibatis.executor.Executor;
 | 
			
		||||
import org.apache.ibatis.mapping.MappedStatement;
 | 
			
		||||
import org.apache.ibatis.mapping.SqlCommandType;
 | 
			
		||||
import org.apache.ibatis.plugin.*;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.annotation.FieldEncrypt;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.autoconfigure.CryptoProperties;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 字段加密拦截器
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
@Intercepts({@Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class}),})
 | 
			
		||||
public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor {
 | 
			
		||||
 | 
			
		||||
    private CryptoProperties properties;
 | 
			
		||||
 | 
			
		||||
    public MyBatisEncryptInterceptor(CryptoProperties properties) {
 | 
			
		||||
        this.properties = properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MyBatisEncryptInterceptor() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Object intercept(Invocation invocation) throws Throwable {
 | 
			
		||||
        Object[] args = invocation.getArgs();
 | 
			
		||||
        MappedStatement mappedStatement = (MappedStatement)args[0];
 | 
			
		||||
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
 | 
			
		||||
        if (!(SqlCommandType.UPDATE == sqlCommandType || SqlCommandType.INSERT == sqlCommandType)) {
 | 
			
		||||
            return invocation.proceed();
 | 
			
		||||
        }
 | 
			
		||||
        Object obj = args[1];
 | 
			
		||||
        // 兼容 MyBatis Plus 封装的 update 相关方法,updateById、update
 | 
			
		||||
        if (obj instanceof Map map) {
 | 
			
		||||
            Object entity = map.get(Constants.ENTITY);
 | 
			
		||||
            this.doEncrypt(this.getEncryptFields(entity), entity);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.doEncrypt(this.getEncryptFields(obj), obj);
 | 
			
		||||
        }
 | 
			
		||||
        return invocation.proceed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 处理加密
 | 
			
		||||
     *
 | 
			
		||||
     * @param fieldList 加密字段列表
 | 
			
		||||
     * @param entity    实体
 | 
			
		||||
     * @throws Exception /
 | 
			
		||||
     */
 | 
			
		||||
    private void doEncrypt(List<Field> fieldList, Object entity) throws Exception {
 | 
			
		||||
        for (Field field : fieldList) {
 | 
			
		||||
            IEncryptor encryptor = super.getEncryptor(field);
 | 
			
		||||
            Object fieldValue = ReflectUtil.getFieldValue(entity, field);
 | 
			
		||||
            // 优先获取自定义对称加密算法密钥,获取不到时再获取全局配置
 | 
			
		||||
            String password = ObjectUtil.defaultIfBlank(field.getAnnotation(FieldEncrypt.class).password(), properties
 | 
			
		||||
                .getPassword());
 | 
			
		||||
            String ciphertext = encryptor.encrypt(fieldValue.toString(), password, properties.getPublicKey());
 | 
			
		||||
            ReflectUtil.setFieldValue(entity, field, ciphertext);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.encryptor;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.crypto.SecureUtil;
 | 
			
		||||
import cn.hutool.crypto.symmetric.AES;
 | 
			
		||||
 | 
			
		||||
import java.nio.charset.StandardCharsets;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * AES(Advanced Encryption Standard) 加/解密处理器
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 美国国家标准与技术研究院(NIST)采纳的对称加密算法标准,提供128位、192位和256位三种密钥长度,以高效和安全性著称。
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
public class AesEncryptor implements IEncryptor {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String encrypt(String plaintext, String password, String publicKey) throws Exception {
 | 
			
		||||
        AES aes = SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8));
 | 
			
		||||
        return aes.encryptHex(plaintext);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String decrypt(String ciphertext, String password, String privateKey) throws Exception {
 | 
			
		||||
        AES aes = SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8));
 | 
			
		||||
        return aes.decryptStr(ciphertext);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.encryptor;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.codec.Base64;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base64 加/解密处理器
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 一种用于编码二进制数据到文本格式的算法,常用于邮件附件、网页传输等场合,但它不是一种加密算法,只提供数据的编码和解码,不保证数据的安全性。
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
public class Base64Encryptor implements IEncryptor {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String encrypt(String plaintext, String password, String publicKey) throws Exception {
 | 
			
		||||
        return Base64.encode(plaintext);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String decrypt(String ciphertext, String password, String privateKey) throws Exception {
 | 
			
		||||
        return Base64.decodeStr(ciphertext);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.encryptor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 加/解密接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
public interface IEncryptor {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 加密
 | 
			
		||||
     *
 | 
			
		||||
     * @param plaintext 明文
 | 
			
		||||
     * @param password  对称加密算法密钥
 | 
			
		||||
     * @param publicKey 非对称加密算法公钥
 | 
			
		||||
     * @return 加密后的文本
 | 
			
		||||
     * @throws Exception /
 | 
			
		||||
     */
 | 
			
		||||
    String encrypt(String plaintext, String password, String publicKey) throws Exception;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 解密
 | 
			
		||||
     *
 | 
			
		||||
     * @param ciphertext 密文
 | 
			
		||||
     * @param password   对称加密算法密钥
 | 
			
		||||
     * @param privateKey 非对称加密算法私钥
 | 
			
		||||
     * @return 解密后的文本
 | 
			
		||||
     * @throws Exception /
 | 
			
		||||
     */
 | 
			
		||||
    String decrypt(String ciphertext, String password, String privateKey) throws Exception;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.encryptor;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.codec.Base64;
 | 
			
		||||
import cn.hutool.crypto.SecureUtil;
 | 
			
		||||
import cn.hutool.crypto.asymmetric.KeyType;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * RSA 加/解密处理器
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 非对称加密算法,由罗纳德·李维斯特(Ron Rivest)、阿迪·沙米尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)于1977年提出,安全性基于大数因子分解问题的困难性。
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
public class RsaEncryptor implements IEncryptor {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String encrypt(String plaintext, String password, String publicKey) throws Exception {
 | 
			
		||||
        return Base64.encode(SecureUtil.rsa(null, publicKey).encrypt(plaintext, KeyType.PublicKey));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String decrypt(String ciphertext, String password, String privateKey) throws Exception {
 | 
			
		||||
        return new String(SecureUtil.rsa(privateKey, null).decrypt(Base64.decode(ciphertext), KeyType.PrivateKey));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.gnu.org/licenses/lgpl.html
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.charles7c.continew.starter.security.crypto.enums;
 | 
			
		||||
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.encryptor.AesEncryptor;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.encryptor.Base64Encryptor;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor;
 | 
			
		||||
import top.charles7c.continew.starter.security.crypto.encryptor.RsaEncryptor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 加密/解密算法枚举
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 1.4.0
 | 
			
		||||
 */
 | 
			
		||||
public enum Algorithm {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * AES
 | 
			
		||||
     */
 | 
			
		||||
    AES(AesEncryptor.class),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * RSA
 | 
			
		||||
     */
 | 
			
		||||
    RSA(RsaEncryptor.class),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Base64
 | 
			
		||||
     */
 | 
			
		||||
    BASE64(Base64Encryptor.class),;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 加密/解密处理器
 | 
			
		||||
     */
 | 
			
		||||
    private final Class<? extends IEncryptor> encryptor;
 | 
			
		||||
 | 
			
		||||
    Algorithm(Class<? extends IEncryptor> encryptor) {
 | 
			
		||||
        this.encryptor = encryptor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Class<? extends IEncryptor> getEncryptor() {
 | 
			
		||||
        return encryptor;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
top.charles7c.continew.starter.security.crypto.autoconfigure.CryptoAutoConfiguration
 | 
			
		||||
		Reference in New Issue
	
	Block a user