Springboot+AOP+注解实现字段AES+Base64加解密

news2024/11/27 17:56:51

AOP实现AES+BASE64加解密

场景如下:
需要对数据库存储的字段,进行加解密的处理。如果都直接写代码的话,那么代码回冗余很多,所以使用AOP+注解去实现。让代码简洁,方便

具体实现如下:

1、依赖
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.20</version>
            <scope>compile</scope>
        </dependency>
2、相关注解
package com.walker.aop.fieldAop.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* author:walker
* time: 2023/12/8
* description:  支持属性加密注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SupportFieldEncrypt {
}

package com.walker.aop.fieldAop.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* author:walker
* time: 2023/12/8
* description: 支持属性解密注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SupportFieldDecrypt {
}

package com.walker.aop.fieldAop.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
* author:walker
* time: 2023/12/8
* description: 属性加密
*/
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldEncrypt {
    /**
    * 具体参数查看FieldEncryptTypeEnums枚举
     * 默认使用AES+BASE64加密
    */
    int type() default 1;
}

package com.walker.aop.fieldAop.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* author:walker
* time: 2023/12/8
* description:  属性解密
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldDecrypt {
    int type() default 1;
}

3、枚举

目前只整合了AES加密的,后续如果需要,可以自己整合

package com.walker.aop.fieldAop.enums;

public enum FieldEncryptTypeEnums {
    AES_BASE64(1,"AES+BASE64");
    private Integer type;
    private String description;

    FieldEncryptTypeEnums(Integer type, String description) {
        this.type = type;
        this.description = description;
    }

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

4、AES加解密工具类
package com.walker.aop.fieldAop;

import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;



import java.nio.charset.StandardCharsets;
/**
* author:walker
* time: 2023/12/7
* description:  AES加解密工具
*/
public class MyAesUtils {

//    密钥,可以自己修改,当然这里可以不在这里写死,但是这里为了方便,就直接写死了
    private final static String AES_KEY="qu6ciLzMME7slNxj";
    private static final AES aes = SecureUtil.aes(AES_KEY.getBytes(StandardCharsets.UTF_8));

    public static String encrypt(String data){
        return Base64.encode(aes.encrypt(data));
    }

    public static String decrypt(String data){
        return aes.decryptStr(Base64.decode(data));
    }

    public static void main(String[] args) {
        String hello = encrypt("hello");
        System.out.println(hello);
        String decrypt = decrypt(hello);
        System.out.println(decrypt);
    }
}

5、切面类
package com.walker.aop.fieldAop.aspect;

import cn.hutool.core.util.ReflectUtil;
import com.walker.aop.fieldAop.enums.FieldEncryptTypeEnums;
import com.walker.aop.fieldAop.MyAesUtils;
import com.walker.aop.fieldAop.annotations.FieldDecrypt;
import com.walker.aop.fieldAop.annotations.FieldEncrypt;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

@Slf4j
//1、使用切面注解
@Aspect
@Component
public class FieldAopAspect {

//    2、这里的引用路径需要根据自己项目的包去调整
    @Pointcut("@annotation(com.walker.aop.fieldAop.annotations.SupportFieldEncrypt)")
    public void supportFieldEncrypt() {};

    @Pointcut("@annotation(com.walker.aop.fieldAop.annotations.SupportFieldDecrypt)")
    public void supportFieldDecrypt() {};

    /**
    * author:walker
    * time: 2023/12/8
    * description:  前置通知 加密处理
    */
//    3、Before代表前置通知
    @Before("supportFieldEncrypt()")
    public void fieldEncryptProcessor(JoinPoint joinPoint){
        //获取参数
        Object[] args = joinPoint.getArgs();

        if(args==null||args.length==0){
            return;
        }
        for (Object arg : args) {
            Class<?> aClass = arg.getClass();
//            获取属性
            Field[] fields = aClass.getDeclaredFields();
            for (Field field : fields) {
//                获取注解
                Annotation[] annotations = field.getAnnotations();
                for (Annotation annotation : annotations) {
//                    判断是否有FieldEncrypt注解
                    if(annotation.annotationType().equals(FieldEncrypt.class)){
                        FieldEncrypt fieldEncrypt= (FieldEncrypt) annotation;
                        int type = fieldEncrypt.type();
                        if(type== FieldEncryptTypeEnums.AES_BASE64.getType()){
//                            如果有注解,则进行加密处理,并使用反射去设置值
                            Object fieldValue = ReflectUtil.getFieldValue(arg, field);
                            if(fieldValue==null) return;
                            String encrypt = MyAesUtils.encrypt(String.valueOf(fieldValue));
                            System.out.println("加密后结果:"+encrypt);
                            ReflectUtil.setFieldValue(arg,field,encrypt);
                        }
                    }
                }
            }
        }
    }


    /**
    * 解密注解
    */
//    返回后通知
    @AfterReturning(value = "supportFieldDecrypt()",returning = "arg")
    public void fieldDecryptProcess(JoinPoint joinPoint, Object arg){
        if(arg==null) return;
//        arg:代表的是返回的结果
        Class<?> aClass = arg.getClass();
//        获取属性
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            Annotation[] annotations = field.getAnnotations();
            for (Annotation annotation : annotations) {
//                判断属性是否有FieldDecrypt注解
                if(annotation.annotationType().equals(FieldDecrypt.class)){
                    FieldDecrypt fieldDecrypt= (FieldDecrypt) annotation;
                    int type = fieldDecrypt.type();
//                    如果存在注解,则进行解密并且重新设置回对象中
                    if(type==FieldEncryptTypeEnums.AES_BASE64.getType()){
                        Object fieldValue = ReflectUtil.getFieldValue(arg, field);
                        System.out.println("解密前结果:"+fieldValue);
                        if(fieldValue==null) return;
                        String decrypt = MyAesUtils.decrypt(String.valueOf(fieldValue));
                        System.out.println("解密后结果:"+decrypt);
                        ReflectUtil.setFieldValue(arg,field,decrypt);
                    }
                }
            }
        }
    }
}

6、测试
  • 测试实体类
package com.walker.aop.fieldAop;

import com.walker.aop.fieldAop.annotations.FieldDecrypt;
import com.walker.aop.fieldAop.annotations.FieldEncrypt;
import lombok.Data;

@Data
public class FieldAopDemo {
    @FieldEncrypt
    @FieldDecrypt
    private String name;
}

  • controller
package com.walker.aop.fieldAop;

import com.walker.aop.fieldAop.annotations.SupportFieldDecrypt;
import com.walker.aop.fieldAop.annotations.SupportFieldEncrypt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/fieldAOP")
public class FieldAOPController {

    @SupportFieldEncrypt
    @GetMapping("/encrypt")
    public void encrypt(FieldAopDemo demo){
        System.out.println(demo);
        return;
    }

    @SupportFieldDecrypt
    @GetMapping("/decrypt")
    public FieldAopDemo decrypt(FieldAopDemo demo){
        System.out.println(demo);
        String name = demo.getName();
        String encrypt = MyAesUtils.encrypt(name);
        System.out.println(encrypt);
        demo.setName(encrypt);
        return demo;
    }
}

之后使用postman调用结果测试:
加密测试:
http://localhost:8080/fieldAOP/encrypt?name=hello
image.png

解密测试:
http://localhost:8080/fieldAOP/decrypt?name=hello
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1296014.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言搭建项目-学生管理系统(非链表)

、 目录 搭建offer.h文件 搭建offer.c中的main函数 密码登入系统 搭建my_oferr.c中的接口函数 使用帮助菜单接口函数 增加学生信息接口函数 查询学生信息接口函数 删除学生信息接口函数 保存学生信息接口 打开文件fopen 关闭文件fclose 判断是否保存文件fwrite 退出执行文件…

TCP传输层详解(计算机网络复习)

介绍&#xff1a;TCP/IP包含了一系列的协议&#xff0c;也叫TCP/IP协议族&#xff0c;简称TCP/IP。该协议族提供了点对点的连接机制&#xff0c;并将传输数据帧的封装、寻址、传输、路由以及接收方式都予以标准化 TCP/IP的分层模型 在讲TCP/IP协议之前&#xff0c;首先介绍一…

【MATLAB】tvfEMD信号分解+FFT+HHT组合算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 TVFEMDFFTHHT组合算法是一种结合了总体变分模态分解&#xff08;TVFEMD&#xff09;、傅里叶变换&#xff08;FFT&#xff09;和希尔伯特-黄变换&#xff08;HHT&#xff09;的信号分解方…

配置Smart Link负载分担示例

Smart Link和Monitor Link简介 定义 Smart Link&#xff0c;又叫做备份链路。一个Smart Link由两个接口组成&#xff0c;其中一个接口作为另一个的备份。Smart Link常用于双上行组网&#xff0c;提供可靠高效的备份和快速的切换机制。 Monitor Link是一种接口联动方案&#…

<习题集><LeetCode><链表><2/19/21/23/24>

目录 2. 两数相加 19. 删除链表的倒数第 N 个结点 21. 合并两个有序链表 23. 合并 K 个升序链表 24. 两两交换链表中的节点 2. 两数相加 https://leetcode.cn/problems/add-two-numbers/ public ListNode addTwoNumbers(ListNode l1, ListNode l2) {//head是cur链表头节点…

拼多多选品大作战:通过热词选利润赛道

相信很多人都听过一句话&#xff1a;找对了风口&#xff0c;猪都能飞起来。 我们电商人也应如此&#xff0c;从行业分析到选品都应快速跟上市场节奏。 今天就给大家分享一下如何通过热词来进行一个行业类目的分析与选择。 01 热词是什么 热词通常指的是热搜词和飙升词&#…

大华DSS S2-045 OGNL表达式注入漏洞复现

0x01 产品简介 大华DSS安防监控系统平台是一款集视频、报警、存储、管理于一体的综合安防解决方案。该平台支持多种接入方式,包括网络视频、模拟视频、数字视频、IP电话、对讲机等。此外,该平台还支持多种报警方式,包括移动侦测、区域入侵、越线报警、人员聚集等。 0x02 漏…

天津大数据培训机构品牌 数据分析师的发展方向

大数据专业还是有一定难度的&#xff0c;毕竟大数据开发技术所包含的编程技术知识是比较杂且多的如果是计算机专业的学生或者自身有一定基础的人学&#xff0c;相对来说会比较容易&#xff0c;但对于零基础小伙伴学习来说&#xff0c;想要学习大数据&#xff0c;难度还是很高的…

C# 编程新手必看,一站式学习网站,让你轻松掌握 C# 技能!

介绍&#xff1a;实际上&#xff0c;您可能弄错了&#xff0c;C#并不是一种独立的编程语言&#xff0c;而是一种由微软公司开发的面向对象的、运行于.NET Framework之上的高级程序设计语言。C#看起来与Java十分相似&#xff0c;但两者并不兼容。 C#的设计目标是简单、强大、类型…

时间序列预测 — VMD-LSTM实现单变量多步光伏预测(Tensorflow):单变量转为多变量

目录 1 数据处理 1.1 导入库文件 1.2 导入数据集 1.3 缺失值分析 2 VMD经验模态分解 3 构造训练数据 4 LSTM模型训练 5 预测 1 数据处理 1.1 导入库文件 import time import datetime import pandas as pd import numpy as np import matplotlib.pyplot as plt f…

系列八、SpringBoot中自定义SpringMVC配置

一、概述 作为Spring家族的明星产品&#xff0c;SpringBoot极大地简化了程序员的日常开发&#xff0c;提高了开发效率。我们很容易得借助于SpringBoot就可以快速开发业务代码。一般情况下&#xff0c;公司的日常开发都是基于web服务的&#xff0c;我们在使用idea等工具初始化一…

SecureCRT9汉化版安装详解

CRT中文版安装说明 一、安装步骤1. 安装注意&#xff1a;2. 右键压缩包&#xff0c;解压到本地文件夹内3. 解压后进入目录&#xff0c;双击CRT_SFX_91_Run_Script激活脚本 3 如果运行结果是下图&#xff0c;就激活成功了&#xff1a;4. 双击桌面的CRT和FX图标5. 如果提示下图&a…

Qt简介、工程文件分离、创建Qt工程、Qt的帮助文档

QT 简介 core&#xff1a;核心模块&#xff0c;非图形的接口类&#xff0c;为其它模块提供支持 gui&#xff1a;图形用户接口&#xff0c;qt5之前 widgets&#xff1a;图形界面相关的类模块 qt5之后的 database&#xff1a;数据库模块 network&#xff1a;网络模块 QT 特性 开…

VisualStudio反汇编功能使用

VisualStudio反汇编功能使用 使用方法 到达断点时&#xff1a;CtrlK&#xff08;松开&#xff09;G&#xff08;后按&#xff09;唤出反汇编界面&#xff0c;就可以看到当前代码对应的汇编语言了 注意&#xff1a;进入反汇编窗口后可以F10单次调试一条汇编指令 其他&#…

3.添加与删除字段

添加字段与删除字段 1.添加字段 因为甲方的业务需求是不停变化的&#xff0c;所以在数据库操作中&#xff0c;添加字段可是常有的事。一个完整的字段包括&#xff1a;字段名、数据类型和完整性约束。 语法规则为&#xff1a; ALTER TABLE 表名 ADD 新字段名 数据类型 [约束条…

SPECPOWER2008

一、前言# 1、软件说明# 官网&#xff1a;SERT套件用户指南2.0.5SPECpower介绍SPEC基准及工具SPECpower_ssj2008测试结果SPECpower_ssj2008-Design_ccs - SPEC# SPEC&#xff08;the Standard Performance Evaluation Corporation&#xff09;是一个由计算机硬件厂商、软件公…

JPA对数据库修改注意点

同一事务中获取不到修改数据 spring-boot-starter-parent版本2.7.12 Dao Query(value "select * from inventory_list where id in (?1) order by id desc",nativeQuery true) List<InventoryListEntity> getByIds(List<Integer> idList);Modifyin…

openharmony 开发环境搭建和系统应用编译傻瓜教程

一、DevEco Studio 安装 当前下载版本有两个&#xff0c;由于低版本配置会有各种问题&#xff0c;我选择高版本安装 低版本下载链接 HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 高版本下载链接 OpenAtom OpenHarmony 解压后安装 双击安装 安装配置 二、创建测…

字符串指令集

字符串指令的格式 例子1就成功发送了指令 例子2就是发送的字符串有误 查询当前位置就会在附加信息中返回当前座位的坐标 第一个指令的参数就是闪灯的两个参数 如第一个示例就是10ms On Time 第二个就是Off Time 使用标准库来接收字符串命令 字符串指令的接收 因为一个指令就是…

vue实现可拖拽列表

直接上代码 <!-- vue实现可拖拽列表 --> <template><div><button click"logcolig">打印数据</button><TransitionGroup name"list" tag"div" class"container"><divclass"item"v-f…