springboot实现敏感字段加密存储,解密显示,通过mybatis,自定义注解+AOP切面,Base64加解密方式实现功能。
1.代码实现:
创建springboot项目
添加依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional> true </optional> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <!--mysql数据库驱动--> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <!--mybatis--> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version> 2.1 . 0 </version> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version> 1.9 . 7 </version> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version> 1.6 </version> |
yml配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
server: port: 8081 spring: #数据库连接配置 datasource: driver- class -name: com.mysql.cj.jdbc.Driver url: jdbc:mysql: //127.0.0.1:3306/test?characterEncoding=utf-8&useSSL=false username: root password: 123456
#mybatis的相关配置 mybatis: #mapper配置文件 mapper-locations: classpath:mapper/*.xml type-aliases- package : com.cxh.mybatis.entity #开启驼峰命名 configuration: map-underscore-to-camel- case : true |
自定义注解
1 2 3 4 5 6 7 |
//表示要加密的字段 @Target ({ElementType.FIELD,ElementType.PARAMETER}) @Retention (RetentionPolicy.RUNTIME) public @interface EncryptField {
String[] value() default "" ; } |
1 2 3 4 5 6 |
//表示需解密 @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface NeedDecrypt {
} |
1 2 3 4 5 |
//表示需加密 @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface NeedEncrypt { } |
AOP切面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
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) { realValue = Base64Util.getBase64(String.valueOf(realValue)); log.info( "加密异常={}" ,e.getMessage()); return String.valueOf(realValue); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
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(); } 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<实体来> 进行反射、解密 private void decryptList(Object obj) throws IllegalAccessException { List<Object> result = new ArrayList<>(); for (Object o : (List<?>) obj) { result.add(o); for (Object object : result) { decryptObj(object); public String decryptValue(Object realValue) { realValue = Base64Util.getFromBase64(String.valueOf(realValue)); } catch (Exception e) { log.info( "解密异常={}" , e.getMessage()); return String.valueOf(realValue); } |
BASE64加解密工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
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) { 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)); } |
控制层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@RestController @RequestMapping ( "/user" ) public class UserController {
@Autowired private UserService userService; @RequestMapping ( "/findAll" ) public List<User> findAll(){ return userService.findAll(); } @RequestMapping ( "/add" ) @NeedEncrypt public int add(User user){ return userService.add(user); @RequestMapping ( "/get" ) @NeedDecrypt public List<User> get(User user){ return userService.get(user); @RequestMapping ( "/getByName" ) public List<User> getByName(String username){ User user = new User(); user.setUsername(Base64Util.getBase64(username)); } |
service实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Service ( "userService" ) public class UserServiceimpl implements UserService {
@Autowired private UserMapper userMapper; @Override public List<User> findAll() { return userMapper.findAll(); } public Integer add(User user) { return userMapper.add(user); public List<User> get(User user) { return userMapper.get(user); } |
userMapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<? 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" > < where > < if test = "id != null and id != ''" > and id = #{id} </ if > < if test = "username != null and username != ''" > and username = #{username} < if test = "password != null and password != ''" > and password = #{password} </ where > </ mapper > |
2.实现效果:
运行项目,打开postman,发起插入请求:localhost:8081/user/add
查看数据库,显示数据已加密
发起查询请求localhost:8081/user/get,显示数据已解密
发起查询所有请求localhost:8081/user/findAll,由于该方法没有添加解密注解,所以数据还是加密的。
到此这篇关于springboot实现敏感字段加密存储,解密显示的文章就介绍到这了,更多相关springboot敏感字段加密存储解密显示内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
原文链接:https://blog.csdn.net/weixin_39220472/article/details/123030651
查看更多关于springboot实现敏感字段加密存储解密显示功能的详细内容...