好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

springboot实现敏感字段加密存储解密显示功能

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实现敏感字段加密存储解密显示功能的详细内容...

  阅读:19次