springboot实现敏感字段加密存储,解密显示,通过mybatis,自定义注解+AOP切面,Base64加解密方式实现功能。

1.代码实现:

创建springboot项目

添加依赖

 <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><!--mysql数据库驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.0</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.6</version></dependency>

yml配置

server:port: 8081
spring:#数据库连接配置datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456#mybatis的相关配置
mybatis:#mapper配置文件mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.cxh.mybatis.entity#开启驼峰命名configuration:map-underscore-to-camel-case: true

自定义注解

//表示要加密的字段
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {String[] value() default "";
}
//表示需解密
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedDecrypt {}
//表示需加密
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedEncrypt {}

AOP切面

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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.util.Objects;//加密AOP
@Slf4j
@Aspect
@Component
public class EncryptAspect {//拦截需加密注解@Pointcut("@annotation(com.cxh.mybatis.test.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);if(field.get(obj) != null){String value = Base64Util.getBase64(String.valueOf(field.get(obj)));field.set(obj, value);}}}}/*** 加密单个值* @param realValue* @return*/public String encryptValue(Object realValue) {try {realValue = Base64Util.getBase64(String.valueOf(realValue));} catch (Exception e) {log.info("加密异常={}",e.getMessage());}return String.valueOf(realValue);}}
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;//解密AOP
@Slf4j
@Aspect
@Component
public class DecryptAspect {//拦截需解密注解@Pointcut("@annotation(com.cxh.mybatis.test.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);if(field.get(obj) != null) {String realValue = (String) field.get(obj);String value = Base64Util.getFromBase64(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 = Base64Util.getFromBase64(String.valueOf(realValue));} catch (Exception e) {log.info("解密异常={}", e.getMessage());}return String.valueOf(realValue);}}

BASE64加解密工具类

import java.io.UnsupportedEncodingException;import org.springframework.stereotype.Component;
import sun.misc.*;public class Base64Util {// 加密public static String getBase64(String str) {byte[] b = null;String s = null;try {b = str.getBytes("utf-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}if (b != null) {s = new BASE64Encoder().encode(b);}return s;}// 解密public static String getFromBase64(String s) {byte[] b = null;String result = null;if (s != null) {BASE64Decoder decoder = new BASE64Decoder();try {b = decoder.decodeBuffer(s);result = new String(b, "utf-8");} catch (Exception e) {e.printStackTrace();}}return result;}public static void main(String[] args) {String a = "123456";String b = getBase64(a);System.out.println(b);System.out.println(getBase64(a));System.out.println(getFromBase64(b));}
}

控制层

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/findAll")public List<User> findAll(){return userService.findAll();}@RequestMapping("/add")@NeedEncryptpublic int add(User user){return userService.add(user);}@RequestMapping("/get")@NeedDecrypt@NeedEncryptpublic List<User> get(User user){return userService.get(user);}@RequestMapping("/getByName")@NeedDecrypt@NeedEncryptpublic List<User> getByName(String username){User user = new User();user.setUsername(Base64Util.getBase64(username));return userService.get(user);}}

service实现类

@Service("userService")
public class UserServiceimpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic List<User> findAll() {return userMapper.findAll();}@Overridepublic Integer add(User user) {return userMapper.add(user);}@Overridepublic List<User> get(User user) {return userMapper.get(user);}
}

userMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.cxh.mybatis.mapper.UserMapper"><select id="findAll" resultType="User">SELECT * FROM tb_user</select><insert id="add" parameterType="User">INSERT INTO tb_user(`id`, `username`, `password`) VALUES (#{id}, #{username}, #{password});</insert><select id="get" resultType="User" parameterType="User">SELECT * FROM tb_user<where><if test="id != null and id != ''">and   id = #{id}</if><if test="username != null and username != ''">and  username = #{username}</if><if test="password != null and password != ''">and   password = #{password}</if></where></select>
</mapper>

2.实现效果:

运行项目,打开postman,发起插入请求:localhost:8081/user/add

查看数据库,显示数据已加密

发起查询请求localhost:8081/user/get,显示数据已解密

发起查询所有请求localhost:8081/user/findAll,由于该方法没有添加解密注解,所以数据还是加密的。

springboot实现敏感字段加密存储,解密显示相关推荐

  1. MYSQL敏感字段加密存储

    出于安全考虑,有时会要求数据表存储的敏感字段加密,比如身份证和手机号. MySQL加密和解密 INSERT INTO user (`idcard`) VALUES(HEX(AES_ENCRYPT('x ...

  2. mybaits plus 字段加密与解密

    mybaits plus 字段加密与解密 写在前面 在我们实际开发中有的时候需要保证数据的安全,那么这个时候我们就需要对我们存储的数据加密,数据加密可以用很多方法实现,比如数据库加密,java代码加密 ...

  3. 敏感字段加密,叶俊峰

    /** 标题:敏感字段加密 | 时间限制:1秒 | 内存限制:262144K | 语言限制:不限 [敏感字段加密]给定一个由多个命令字组成的命令字符串: 1.字符串长度小于等于127字节,只包含大小写 ...

  4. Django 字段加密存储并支持检索

    本文将介绍一种在 Django 框架内将数据进行加密存储到数据库并且支持检索的方法,此方法采用单向加密和非对称加密解密技术结合来实现. 概念解释: 非对称加密算法需要两个密钥来进行加密和解密,这两个秘 ...

  5. Java序列化敏感字段加密

    在序列化过程中,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化,如果没有这样的方法,则默认调用是 ObjectOutputStre ...

  6. 华为od统一考试B卷【敏感字段加密】JavaScript 实现

       所有题目均有五种语言实现.C语言实现目录.C++ 实现目录.Python实现目录.Java实现目录.JavaScript实现目录 题目 给定一个由多个命令字组成的命令字符串: 1.字符串长度小于 ...

  7. Springboot项目如何设计接口中敏感字段模糊查询?

    目录 前言 场景分析 实现方案 环境配置 依赖配置 代码实现 总结 前言 在<Springboot项目如何设计接口中敏感字段的加密.解密>和<Springboot项目如何设计接口中敏 ...

  8. java使用mybatis拦截器对数据库敏感字段进行加密存储并解密

    记录业务中遇到的使用场景:灵活对数据库敏感字段进行加密和解密 文章目录 前言 一.创建数据库表和实体类 二.Mapper.Service.Controller等 三.自定义注解 四.加密工具类 五.参 ...

  9. MySql字段内容加密与解密

    AES和DES 对于存储在数据库中的敏感信息,往往需要对其进行加密.MySql提供了多种加密方式,其中两种为AES和DES. 这两种方式用法类似.性能上,AES各方面都略强于DES.因此推荐使用AES ...

最新文章

  1. 260万奖金池!目标检测新赛事来了
  2. Nginx 配置https 自动续期
  3. 4.1_ 1_ 初识文件管理
  4. 给i茅台APP提几个建议
  5. phpcmsV9 关于phpcms根目录下ico图标,改了没效果的解决办法?
  6. 大数据,并非一蹴而就
  7. Scanner--控制台输入
  8. 兄弟连php课件,兄弟连php课件
  9. 下载 Eclipse 中文语言包进行汉化
  10. Android 源码编译步骤实录
  11. oracle、mysql、sqlserver、pg数据库去重实现方案总结
  12. 《学习笔记》使用AngularJS模板来创建视图
  13. html 规定输入框必须输入
  14. C语言10.10,查找英文的星期几
  15. button loading indicators
  16. 使用Python提取Excel中单元格中的某一段内容(包含某特定字符且前后以逗号作为分隔符的内容)
  17. 山经·南山经:招摇山
  18. C++ —— (两个经纬度计算距离、方位角)、(经纬度A+距离+方位,计算目标经纬度)、(多个经纬度计算面积)
  19. SQLsever数据库实例是啥子
  20. Pycharm中c、m、F、f、v、p分别代表的含义

热门文章

  1. vue项目首屏加载慢解决方案
  2. 查询速度至少为160MHz的PC的制造商
  3. 如何确认 fastboot unlock 解锁成功,如何确认DM-verity 已关闭
  4. JS脚本错误80020101以及FCKedito未定义的一种解决办法
  5. mysql report-port_mysql性能优化工具mysqlreport
  6. 在与SQL Server建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且SQL Server已配置为允许远程连接。(provider:命名管道提供程序,
  7. Squid TCP_MISS/000 的意义
  8. 计算机毕业设计springboot轰趴馆管理
  9. 中文情感分析 (Sentiment Analysis) 的难点在哪?现在做得比较好的有哪几家?
  10. 产品经理的金字塔之旅---将“打杂”的实习经历描述的高大上!!!