当前位置: 首页 > news >正文

springboot aop方式实现敏感数据自动加解密

一、前言
在实际项目开发中,可能会涉及到一些敏感信息,那么我们就需要对这些敏感信息进行加密处理,
也就是脱敏,比如像手机号、身份证号等信息。如果我们只是在接口返回后再去做替换处理,则代码会显得非常冗余,那么实际可以通过注解的方式实现数据脱敏。

二、具体实现
1.定义一个标记于方法上的注解。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)         //METHOD 说明该注解只能用在方法上
@Retention(RetentionPolicy.RUNTIME) //RUNTIME 说明该注解在运行时生效
public @interface DataEncryption {}

2.定义一个数据解密的注解。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)         //METHOD 说明该注解只能用在方法上
@Retention(RetentionPolicy.RUNTIME) //RUNTIME 说明该注解在运行时生效
public @interface DataDecryption {}

3.定义一个在字段上,且有值的注解。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)           //FIELD 说明该注解只能用在字段上
@Retention(RetentionPolicy.RUNTIME)  //RUNTIME 说明该注解在运行时生效
public @interface EncryptField {//脱敏枚举值DesensitizationEnum value();
}

4.定义一个在字段上,且有值的注解。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)           //FIELD 说明该注解只能用在字段上
@Retention(RetentionPolicy.RUNTIME)  //RUNTIME 说明该注解在运行时生效
public @interface DecryptField {//脱敏枚举值DesensitizedUtil.DesensitizedType value();
}

5.定义用户返回的实体类。


import com.test.annotation.DecryptField;
import com.test.enums.DesensitizationEnum;
import com.test.utils.AesUtil;import java.lang.reflect.Field;
import lombok.Data;
// 用户信息返回实体类
@Data
public class UserResVo {@DecryptField(DesensitizedUtil.DesensitizedType.CHINESE_NAME)@EncryptFieldprivate String name;@EncryptField@EncryptField(DesensitizedUtil.DesensitizedType.ID_CARD)private String idCard;@EncryptField@EncryptField(DesensitizedUtil.DesensitizedType.MOBILE_PHONE)private String phone;@EncryptField@EncryptField(DesensitizedUtil.DesensitizedType.EMAIL)private String email;
}

6.定义AOP注解实现

import cn.hutool.crypto.digest.DigestUtil;
import com.google.gson.Gson;
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.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.Objects;@Aspect
@Component
@Slf4j
public class SecretAopAspect {@Pointcut("@annotation(com.secret.annotation.DataEncryption)")public void encryptAopCut() {}@Pointcut("@annotation(com.secret.annotation.DataDecryption)")public void decryptAopCut() {}/*** @method encryptMethodAop* @desc 加密方法* @Param: joinPoint*/@Around("encryptAopCut()")public Object encryptMethodAop(ProceedingJoinPoint joinPoint) {Object responseObj = null;try {responseObj = joinPoint.proceed();this.handleEncrypt(responseObj);//md5加密,在相应里面设置签名值String md5Data = DigestUtil.md5Hex(new Gson().toJson(responseObj));HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();response.setHeader("md5",md5Data);} catch (Throwable throwable) {throwable.printStackTrace();this.log.error("encryptMethodAop处理出现异常{}", throwable);}return responseObj;}/*** @method decryptMethodAop* @desc 解密方法* @Param: joinPoint*/@Around("decryptAopCut()")public Object decryptMethodAop(ProceedingJoinPoint joinPoint) {Object responseObj = null;try {responseObj = joinPoint.getArgs()[0];//throw new RuntimeException("md5校验失败");this.handleDecrypt(responseObj);//生成md5签名String md5 = DigestUtil.md5Hex(new Gson().toJson(responseObj));System.out.println(md5);//从请求头获取前端传过来的签名String origianlMd5 = "";HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();origianlMd5 = request.getHeader("md5");//比对签名if(md5.equals(origianlMd5)){//方便调试,不比对前端签名responseObj = joinPoint.proceed();}else{throw new Exception("参数的md5校验不同,可能存在篡改行为,请检查!");}} catch (Throwable throwable) {throwable.printStackTrace();log.error("decryptMethodAop处理出现异常{}", throwable);}return responseObj;}/*** @method handleEncrypt* @desc 对实体么个属性进行加密* @Param: requestObj* @return void*/private void handleEncrypt(Object requestObj) throws Exception {if (!Objects.isNull(requestObj)) {Field[] fields = requestObj.getClass().getDeclaredFields();Field[] fieldsCopy = fields;int fieldLength = fields.length;for(int i = 0; i < fieldLength; ++i) {Field field = fieldsCopy[i];boolean hasSecureField = field.isAnnotationPresent(EncryptField.class);if (hasSecureField) {field.setAccessible(true);String plaintextValue = (String)field.get(requestObj);String cipherText = AesUtil.encrypt(plaintextValue);field.set(requestObj, cipherText);}}}}/*** @method handleDecrypt* @desc 对实体么个属性进行解密* @Param: responseObj* @return*/private Object handleDecrypt(Object responseObj) throws Exception {if (Objects.isNull(responseObj)) {return null;} else {Field[] fields = responseObj.getClass().getDeclaredFields();Field[] fieldsCopy = fields;int fieldLength = fields.length;for(int i = 0; i < fieldLength; ++i) {Field field = fieldsCopy[i];boolean hasSecureField = field.isAnnotationPresent(DecryptField.class);if (hasSecureField) {DecryptField decryptField = field.getAnnotation(DecryptField.class);field.setAccessible(true);String encryptValue = (String)field.get(responseObj);encryptValue = AesUtil.decrypt(encryptValue,decryptField.getValue());field.set(responseObj, encryptValue);}}return responseObj;}}}

7.加解密工具类

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;public class AesUtil {// 默认16位 或 128 256位public static String AES_KEY = "EN#qerdfdshbd110";public static AES aes = SecureUtil.aes(AES_KEY.getBytes());public static String encrypt(Object obj) {return aes.encryptHex((String) obj);}public static String decrypt(Object obj, DesensitizedUtil.DesensitizedType desensitizedType) {// 解密String decrypt = decrypt(obj);// 脱敏return DesensitizedUtil.desensitized(decrypt, desensitizedType);}public static String decrypt(Object obj) {return aes.decryptStr((String) obj, CharsetUtil.CHARSET_UTF_8);}
}

8.接着就可以测试了。

相关文章:

springboot aop方式实现敏感数据自动加解密

一、前言 在实际项目开发中&#xff0c;可能会涉及到一些敏感信息&#xff0c;那么我们就需要对这些敏感信息进行加密处理&#xff0c; 也就是脱敏&#xff0c;比如像手机号、身份证号等信息。如果我们只是在接口返回后再去做替换处理&#xff0c;则代码会显得非常冗余&#xf…...

RabbitMQ---work消息模型

1、work消息模型 工作队列或者竞争消费者模式 在第一篇教程中&#xff0c;我们编写了一个程序&#xff0c;从一个命名队列中发送并接受消息。在这里&#xff0c;我们将创建一个工作队列&#xff0c;在多个工作者之间分配耗时任务。 工作队列&#xff0c;又称任务队列。主要思…...

GitRedisNginx合集

目录 文件传下载 Git常用命令 Git工作区中文件的状态 远程仓库操作 分支操作 标签操作 idea中使用git 设置git.exe路径 操作步骤 linux配置jdk 安装tomcat 查看是否启动成功 查看tomcat进程 防火墙操作 开放指定端口并立即生效 安装mysql 修改mysql密码 安装lrzsz软…...

系统架构设计师之缓存技术:Redis与Memcache能力比较

系统架构设计师之缓存技术&#xff1a;Redis与Memcache能力比较...

02.sqlite3学习——嵌入式数据库的基本要求和SQLite3的安装

目录 嵌入式数据库的基本要求和SQLite3的安装 嵌入式数据库的基本要求 常见嵌入式数据库 sqlite3简介 SQLite3编程接口模型 ubuntu 22.04下的SQLite安装 嵌入式数据库的基本要求和SQLite3的安装 嵌入式数据库的基本要求 常见嵌入式数据库 sqlite3简介 SQLite3编程接口模…...

AIGC ChatGPT 按年份进行动态选择的动态图表

动态可视化分析的好处与优势&#xff1a; 1. 提高信息理解性&#xff1a;可视化分析使得大量复杂的数据变得易于理解&#xff0c;通过图表、颜色、形状、尺寸等方式&#xff0c;能够直观地表现不同的数据关系和模式。 2. 加快决策速度&#xff1a;数据可视化可以帮助用户更快…...

分布式—雪花算法生成ID

一、简介 1、雪花算法的组成&#xff1a; 由64个Bit(比特)位组成的long类型的数字 0 | 0000000000 0000000000 0000000000 000000000 | 00000 | 00000 | 000000000000 1个bit&#xff1a;符号位&#xff0c;始终为0。 41个bit&#xff1a;时间戳&#xff0c;精确到毫秒级别&a…...

Python语言实现React框架

迷途小书童的 Note 读完需要 6分钟 速读仅需 2 分钟 1 reactpy 介绍 reactpy 是一个用 Python 语言实现的 ReactJS 框架。它可以让我们使用 Python 的方式来编写 React 的组件&#xff0c;构建用户界面。 reactpy 的目标是想要将 React 的优秀特性带入 Python 领域&#xff0c;…...

Netty入门学习和技术实践

Netty入门学习和技术实践 Netty1.Netty简介2.IO模型3.Netty框架介绍4. Netty实战项目学习5. Netty实际应用场景6.扩展 Netty 1.Netty简介 Netty是由JBOSS提供的一个java开源框架&#xff0c;现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具&…...

MySQL详细安装与配置

免安装版的Mysql MySQL关是一种关系数据库管理系统&#xff0c;所使用的 SQL 语言是用于访问数据库的最常用的 标准化语言&#xff0c;其特点为体积小、速度快、总体拥有成本低&#xff0c;尤其是开放源码这一特点&#xff0c;在 Web 应用方面 MySQL 是最好的 RDBMS(Relation…...

裸露土堆识别算法

裸露土堆识别算法首先利用图像处理技术&#xff0c;提取出图像中的土堆区域。裸露土堆识别算法首通过计算土堆中被绿色防尘网覆盖的比例&#xff0c;判断土堆是否裸露。若超过40%的土堆没有被绿色防尘网覆盖&#xff0c;则视为裸露土堆。当我们谈起计算机视觉时&#xff0c;首先…...

说说你对Redux的理解?其工作原理?

文章目录 redux&#xff1f;工作原理如何使用后言 redux&#xff1f; React是用于构建用户界面的&#xff0c;帮助我们解决渲染DOM的过程 而在整个应用中会存在很多个组件&#xff0c;每个组件的state是由自身进行管理&#xff0c;包括组件定义自身的state、组件之间的通信通…...

《基于 Vue 组件库 的 Webpack5 配置》7.路径别名 resolve.alias 和 性能 performance

路径别名 resolve.alias const path require(path);module.exports {resolve: {alias: {"": path.resolve(__dirname, "./src/"),"assets": path.resolve(__dirname, "./src/assets/"),"mixins": path.resolve(__dirname,…...

基于PaddleOCR2.7.0发布WebRest服务测试案例

基于PaddleOCR2.7.0发布WebRest服务测试案例 #WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. #警告&#xff1a;这是一个开发服务器。不要在生产部署中使用它。请改用生产WSGI服务器。 输出结果…...

Solidity 合约安全,常见漏洞 (下篇)

Solidity 合约安全&#xff0c;常见漏洞 &#xff08;下篇&#xff09; Solidity 合约安全&#xff0c;常见漏洞 &#xff08;上篇&#xff09; 不安全的随机数 目前不可能用区块链上的单一交易安全地产生随机数。区块链需要是完全确定的&#xff0c;否则分布式节点将无法达…...

nodejs根据pdf模板填入中文数据并生成新的pdf文件

导入pdf-lib库和fontkit npm install pdf-lib fs npm install pdf-lib/fontkit 具体代码 const { PDFDocument, StandardFonts } require(pdf-lib); const fs require(fs); const fontkit require(pdf-lib/fontkit) let pdfDoc let font async function fillPdfForm(temp…...

UE4与pycharm联合仿真的调试问题及一些仿真经验

文章目录 ue4与pycharm联合仿真的调试问题前言ue4端的debug过程pycharm端 一些仿真经验小结 ue4与pycharm联合仿真的调试问题 前言 因为在实验中我需要用到py代码输出控制信息给到ue4中&#xff0c;并且希望看到py端和ue端分别在运行过程中的输出以及debug调试。所以&#xf…...

【数据分析】波士顿矩阵

波士顿矩阵是一种用于分析市场定位和企业发展战略的管理工具。由美国波士顿咨询集团&#xff08;Boston Consulting Group&#xff09;于1970年提出&#xff0c;并以该集团命名。 波士顿矩阵主要基于产品生命周期和市场份额两个维度&#xff0c;将企业的产品或业务分为四个象限…...

sizeof和strlen的对比

文章目录 &#x1f6a9;前言&#x1f6a9;sizeof&#x1f6a9;strlen&#x1f6a9;sizeof和strlen对比 &#x1f6a9;前言 很多小白在学习中&#xff0c;经常将sizeof和strlen弄混了。本篇文章&#xff0c;小编讲解一下sizeof和strlen的区别。&#x1f937;‍♂️ &#x1f6a9…...

Flutter系列文章-Flutter 插件开发

在本篇文章中&#xff0c;我们将学习如何开发 Flutter 插件&#xff0c;实现 Flutter 与原生平台的交互。我们将详细介绍插件的开发过程&#xff0c;包括如何创建插件项目、实现方法通信、处理异步任务等。最后&#xff0c;我们还将演示如何将插件打包并发布到 Flutter 社区。 …...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...