Springboot AOP实现指定敏感字段数据加密 (数据加密篇 二)

简介: Springboot AOP实现指定敏感字段数据加密 (数据加密篇 二)

前言



最近项目组开始关注一些敏感数据的明文相关的事宜 , 其实这些东西也是都有非常成熟的解决方案。 既然最近着手去解决这些事情,那么也顺便给还未了解的大伙普及一下。


这个系列就暂短的分成三篇 :


第一篇    yml配置文件里敏感数据的加密

Springboot yml配置参数数据加密 (数据加密篇 一)_默默不代表沉默-CSDN博客


第二篇    传入数据敏感数据的加密存储


第三篇     使用mysql加解密函数轻松实现  


Springboot 使用mysql加密解密函数 (数据加密篇 三)_默默不代表沉默-CSDN博客


本篇是第二篇 ,基于第一篇已经整合了jasypt 的基础上 。


正文



内容:


1. 插入数据 自定义注解方式  对 指定接口方法 的 参数的指定字段进行 加密存储;


2.对数据内的加密数据,进行解密返回


先看看效果 :


数据存入数据库表内, 手机号phone和邮箱email 属于敏感数据,我们需要密文存储 :


image.png


查询解密返回:


image.png


1.  自定义注解 加密标识注解  NeedEncrypt.java :


import java.lang.annotation.*;
/**
 * @Author JCccc
 * @Description 需加密
 * @Date 2021/7/23 11:55
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedEncrypt {
}


2.自定义注解 需加密字段标识注解 EncryptField.java :


/**
 * @Author JCccc
 * @Description
 * @Date 2021/7/23 11:55
 */
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
    String[] value() default "";
}


3.加密逻辑的aop处理器  EncryptAspect.java :


import com.elegant.dotest.aop.annotation.EncryptField;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Objects;
/**
 * @Author JCccc
 * @Description
 * @Date 2021/9/14 8:55
 */
@Slf4j
@Aspect
@Component
public class EncryptAspect {
    @Autowired
    private StringEncryptor stringEncryptor;
    @Pointcut("@annotation(com.elegant.dotest.aop.annotation.NeedEncrypt)")
    public void pointCut() {
    }
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //加密
        encrypt(joinPoint);
        return joinPoint.proceed();
    }
    public void encrypt(ProceedingJoinPoint joinPoint)  {
        Object[] objects=null;
        try {
             objects = joinPoint.getArgs();
            if (objects.length != 0) {
                for (int i = 0; i < objects.length; i++) {
                    //抛砖引玉 ,可自行扩展其他类型字段的判断
                    if (objects[i] instanceof String) {
                        objects[i] = encryptValue(objects[i]);
                    } else {
                        encryptObject(objects[i]);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 加密对象
     * @param obj
     * @throws IllegalAccessException
     */
    private void encryptObject(Object obj) throws IllegalAccessException {
        if (Objects.isNull(obj)) {
            log.info("当前需要加密的object为null");
            return;
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean containEncryptField = field.isAnnotationPresent(EncryptField.class);
            if (containEncryptField) {
                //获取访问权
                field.setAccessible(true);
                String value = stringEncryptor.encrypt(String.valueOf(field.get(obj)));
                field.set(obj, value);
            }
        }
    }
    /**
     * 加密单个值
     * @param realValue
     * @return
     */
    public String encryptValue(Object realValue) {
        try {
            realValue = stringEncryptor.encrypt(String.valueOf(realValue));
        } catch (Exception e) {
            log.info("加密异常={}",e.getMessage());
        }
        return String.valueOf(realValue);
    }
}


4. 插入user表 使用的 User.java :

 

import com.elegant.dotest.aop.annotation.EncryptField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
 * @Author JCccc
 * @Description
 * @Date 2021/9/14 8:55
 */
@Data
@Accessors(chain = true)
public class User {
    private Integer id;
    private String name;
    @EncryptField
    private String phone;
    @EncryptField
    private String email;
    private Integer age;
}


可以看到,手机号phone 和 邮箱 email 两个字段,我们做了注解 @EncryptField 标识:


image.png


ok,我们写个测试接口,使用 @NeedEncrypt 注解标识这个接口需要进行加密拦截 :


image.png


使用postman调用一下测试接口:


image.png 


可以看下数据库,数据已经加密存储成功:


image.png


接下来是查询解密环节:


解密这里其实有些小讲究。 因为查询出来的数据有可能是单个实体,也可能是List (其实甚至是Map或者Set,又或者是 分页数据类)


所以本文将会以 最常用的 单个实体 、 List<实体> 为例子,去做解密。


1.解密自定义注解 NeedDecrypt.java :


/**
 * @Author JCccc
 * @Description 需解密
 * @Date 2021/7/23 11:55
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedDecrypt {
}


2. 解密逻辑的aop处理器  DecryptAspect.java :

 

import com.elegant.dotest.aop.annotation.EncryptField;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
 * @Author JCccc
 * @Description
 * @Date 2021/9/14 8:55
 */
@Slf4j
@Aspect
@Component
public class DecryptAspect {
    @Autowired
    private StringEncryptor stringEncryptor;
    @Pointcut("@annotation(com.elegant.dotest.aop.annotation.NeedDecrypt)")
    public void pointCut() {
    }
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //解密
        Object result = decrypt(joinPoint);
        return result;
    }
    public Object decrypt(ProceedingJoinPoint joinPoint) {
        Object result = null;
        try {
            Object obj = joinPoint.proceed();
            if (obj != null) {
                //抛砖引玉 ,可自行扩展其他类型字段的判断
                if (obj instanceof String) {
                    decryptValue(obj);
                } else {
                    result = decryptData(obj);
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return result;
    }
    private Object decryptData(Object obj) throws IllegalAccessException {
        if (Objects.isNull(obj)) {
            return null;
        }
        if (obj instanceof ArrayList) {
            decryptList(obj);
        } else {
            decryptObj(obj);
        }
        return obj;
    }
    /**
     * 针对单个实体类进行 解密
     * @param obj
     * @throws IllegalAccessException
     */
    private void decryptObj(Object obj) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean hasSecureField = field.isAnnotationPresent(EncryptField.class);
            if (hasSecureField) {
                field.setAccessible(true);
                String realValue = (String) field.get(obj);
                String value = stringEncryptor.decrypt(realValue);
                field.set(obj, value);
            }
        }
    }
    /**
     * 针对list<实体来> 进行反射、解密
     * @param obj
     * @throws IllegalAccessException
     */
    private void decryptList(Object obj) throws IllegalAccessException {
        List<Object> result = new ArrayList<>();
        if (obj instanceof ArrayList) {
            for (Object o : (List<?>) obj) {
                result.add(o);
            }
        }
        for (Object object : result) {
            decryptObj(object);
        }
    }
    public String decryptValue(Object realValue) {
        try {
            realValue = stringEncryptor.encrypt(String.valueOf(realValue));
        } catch (Exception e) {
            log.info("解密异常={}", e.getMessage());
        }
        return String.valueOf(realValue);
    }
}


然后我们对一个查询方法进行测试 :


image.png

我们先试一下查询单条数据的:


使用@NeedDecrypt注解标记这个接口需要数据解密:


image.png


调用接口看看结果:


image.png


然后是多条数据List<User> 返回的接口:


image.png


调用接口测试看看结果:


image.png

相关文章
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
606 6
|
7月前
|
人工智能 安全 Java
Spring Boot yml 配置敏感信息加密
本文介绍了如何在 Spring Boot 项目中使用 Jasypt 实现配置文件加密,包含添加依赖、配置密钥、生成加密值、在配置中使用加密值及验证步骤,并提供了注意事项,确保敏感信息的安全管理。
1382 1
|
存储 安全 数据安全/隐私保护
Codota的数据加密技术包括静态数据加密和传输中的数据加密
Codota的数据加密技术包括静态数据加密和传输中的数据加密
252 4
|
11月前
|
编解码 安全 Java
如何在Spring Boot中实现数据加密
本文介绍了如何在Spring Boot中实现数据加密。首先阐述了数据加密的重要性与应用场景,接着讲解了对称加密和非对称加密的原理及区别。通过添加依赖、配置加密算法、编写加密工具类等步骤,展示了具体实现方法,并在业务代码中应用加密技术保护敏感数据。希望对开发者有所帮助。
829 7
|
11月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
1480 0
|
11月前
|
Java 开发者 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——什么是AOP
本文介绍了Spring Boot中的切面AOP处理。AOP(Aspect Oriented Programming)即面向切面编程,其核心思想是分离关注点。通过AOP,程序可以将与业务逻辑无关的代码(如日志记录、事务管理等)从主要逻辑中抽离,交由专门的“仆人”处理,从而让开发者专注于核心任务。这种机制实现了模块间的灵活组合,使程序结构更加可配置、可扩展。文中以生活化比喻生动阐释了AOP的工作原理及其优势。
564 0
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
1010 8
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
1059 5
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
302 8
|
12月前
|
云安全 安全 数据建模
《数字证书:互联网世界的"身份证"与"防盗门"》 ——揭秘网络安全背后的加密江湖
在2023年某深夜,上海陆家嘴金融公司机房遭遇黑客攻击,神秘青铜大门与九大掌门封印的玉牌突现,阻止了入侵。此门象征数字证书,保障网络安全。数字证书如验钞机识别假币,保护用户数据。它通过SSL/TLS加密、CA认证和非对称加密,构建安全通信。证书分为DV、OV、EV三类,分别适合不同场景。忽视证书安全可能导致巨额损失。阿里云提供一站式证书服务,助力企业部署SSL证书,迎接未来量子计算和物联网挑战。