springboot 实现数据加密传输,RSA+AOP+自定义注解

本文介绍了如何在SpringBoot应用中使用RSA加密技术结合AOP切面和自定义注解实现数据的安全传输。通过创建RSA密钥对,定义注解标记加密需求,以及编写AOP切面处理加密解密,确保敏感数据在传输过程中的安全性。示例代码详细展示了整个流程。
摘要由CSDN通过智能技术生成

springboot 实现数据加密传输,RSA+AOP+自定义注解!

原创,请勿转载!!!!!
要是实现了,帮忙点个赞!!!!!

目录

1、RSA工具类;
2、自定义注解;
3、AOP切面;
4、实现效果。

1、RSA工具类


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class RSAUtils {
    protected static final Log log = LogFactory.getLog(RSAUtils.class);
    private static String KEY_RSA_TYPE = "RSA";
    private static String KEY_RSA_TYPE_ALL = "RSA/ECB/PKCS1Padding";
    private static int KEY_SIZE = 1024;//JDK方式RSA加密最大只有1024位
    private static int ENCODE_PART_SIZE = KEY_SIZE / 8;
    public static final String PUBLIC_KEY_NAME = "public";
    public static final String PRIVATE_KEY_NAME = "private";
    //私钥,可以为配置项
    private static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4H/rQBqZu+pO/ciRC4WGkoBkev+qPjPCQSpxsxMo+ksvHxfEvxn/7Vecuz3Y/xIRVH0Cy+MuFWSq/O8xCg2ioGMkqpEdkDsn3XLoeed5UYHj6FWxJPMTjlWau2j647fYhixdqNk6BJ6/6TP+d9wJ+McKNQ+KcPO1HEIGjHk2ZbQIDAQAB";
//公钥     可以为配置项
    private static String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALgf+tAGpm76k79yJELhYaSgGR6/6o+M8JBKnGzEyj6Sy8fF8S/Gf/tV5y7Pdj/EhFUfQLL4y4VZKr87zEKDaKgYySqkR2QOyfdcuh553lRgePoVbEk8xOOVZq7aPrjt9iGLF2o2ToEnr/pM/533An4xwo1D4pw87UcQgaMeTZltAgMBAAECgYEAgT9RnH1Oj1CuLhE9iwUSubD4cTFewe25YFA/hcqN/WamTVGRgGviotcmNSHEa/bSvb32eKtUkgKJkzuyom4EI+p02Wbp7C/1s6bu72Ga2UfEbeGpu4ETS+jcfq4zy+AdeaKgkwYqteBF+Z2BZWvABZi4dPzJOY/Xb/EXqToSpjECQQDfV6HtRrDdsyAilASozcvSOaym32KbittfR7eOTnBh9Pvoq/S0eX+gWx4bi8Ww4P9QdimmugltqryufktgqDebAkEA0wxSzhbJLFC3U5lBdPHYNLCodZBpS97POkf4Mbne+SeferKRLpijtn++Ghu/+6qrgU5zHxgFozQ0/qEOf8+3lwJAc8QGqOjFcIUSmRnEOINDrNo8RdrwT9Nv1jlkSZ0a34uOr5HCK3H213Wja3/NntthO6GkAUnY7UFcv82y4I0RFQJAI1vZM7YVllsfm939XX53XryKPMgpHBEEXxtXtd0SQmQlEAWC1W+1Xgog63biv2NkwJFIMFlx+Fny1wZcy4UdmQJBAK2kkQ1G/dM9mZckDqGR3pB2EgQB4ovo/NloXOavp/u6hu7WukGUqdJdBuhdCV6bNsqes1tdm4hDF+4oBPsd3l4=";

    /**
     * 创建公钥秘钥
     *
     * @return
     */
    public static Map<String, String> createRSAKeys() {
        Map<String, String> keyPairMap = new HashMap<>();
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_RSA_TYPE);
            keyPairGenerator.initialize(KEY_SIZE, new SecureRandom());
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            String publicKeyValue = Base64.encodeBase64String(keyPair.getPublic().getEncoded());
            String privateKeyValue = Base64.encodeBase64String(keyPair.getPrivate().getEncoded());
            keyPairMap.put(PUBLIC_KEY_NAME, publicKeyValue);
            keyPairMap.put(PRIVATE_KEY_NAME, privateKeyValue);
        } catch (NoSuchAlgorithmException e) {
            log.error("当前JDK版本没找到RSA加密算法!");
            e.printStackTrace();
        }
        return keyPairMap;
    }

    /**
     * 公钥加密
     * 描述:
     * 1字节 = 8位;
     * 最大加密长度如 1024位私钥时,最大加密长度为 128-11 = 117字节,不管多长数据,加密出来都是 128 字节长度。
     *
     * @param sourceStr
     * @param publicKeyBase64Str
     * @return
     */
    public static String encode(String sourceStr, String publicKeyBase64Str) {
        byte[] publicBytes = Base64.decodeBase64(publicKeyBase64Str);
        //公钥加密
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicBytes);
        List<byte[]> alreadyEncodeListData = new LinkedList<>();

        int maxEncodeSize = ENCODE_PART_SIZE - 11;
        String encodeBase64Result = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA_TYPE);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(KEY_RSA_TYPE_ALL);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] sourceBytes = sourceStr.getBytes("utf-8");
            int sourceLen = sourceBytes.length;
            for (int i = 0; i < sourceLen; i += maxEncodeSize) {
                int curPosition = sourceLen - i;
                int tempLen = curPosition;
                if (curPosition > maxEncodeSize) {
                    tempLen = maxEncodeSize;
                }
                byte[] tempBytes = new byte[tempLen];//待加密分段数据
                System.arraycopy(sourceBytes, i, tempBytes, 0, tempLen);
                byte[] tempAlreadyEncodeData = cipher.doFinal(tempBytes);
                alreadyEncodeListData.add(tempAlreadyEncodeData);
            }
            int partLen = alreadyEncodeListData.size();//加密次数

            int allEncodeLen = partLen * ENCODE_PART_SIZE;
            byte[] encodeData = new byte[allEncodeLen];//存放所有RSA分段加密数据
            for (int i = 0; i < partLen; i++) {
                byte[] tempByteList = alreadyEncodeListData.get(i);
                System.arraycopy(tempByteList, 0, encodeData, i * ENCODE_PART_SIZE, ENCODE_PART_SIZE);
            }
            encodeBase64Result = Base64.encodeBase64String(encodeData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encodeBase64Result;
    }

    /**
     * 公钥加密
     *
     * @param sourceStr
     * @return
     */
    public static String encode(String sourceStr) {
        return encode(sourceStr, publicKey);
    }

    /**
     * 私钥解密
     *
     * @param sourceBase64RSA
     * @param privateKeyBase64Str
     */
    public static String decode(String sourceBase64RSA, String privateKeyBase64Str) {
        byte[] privateBytes = Base64.decodeBase64(privateKeyBase64Str);
        byte[] encodeSource = Base64.decodeBase64(sourceBase64RSA);
        int encodePartLen = encodeSource.length / ENCODE_PART_SIZE;
        List<byte[]> decodeListData = new LinkedList<>();//所有解密数据
        String decodeStrResult = null;
        //私钥解密
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateBytes);
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA_TYPE);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(KEY_RSA_TYPE_ALL);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            int allDecodeByteLen = 0;//初始化所有被解密数据长度
            for (int i = 0; i < encodePartLen; i++) {
                byte[] tempEncodedData = new byte[ENCODE_PART_SIZE];
                System.arraycopy(encodeSource, i * ENCODE_PART_SIZE, tempEncodedData, 0, ENCODE_PART_SIZE);
                byte[] decodePartData = cipher.doFinal(tempEncodedData);
                decodeListData.add(decodePartData);
                allDecodeByteLen += decodePartData.length;
            }
            byte[] decodeResultBytes = new byte[allDecodeByteLen];
            for (int i = 0, curPosition = 0; i < encodePartLen; i++) {
                byte[] tempSorceBytes = decodeListData.get(i);
                int tempSourceBytesLen = tempSorceBytes.length;
                System.arraycopy(tempSorceBytes, 0, decodeResultBytes, curPosition, tempSourceBytesLen);
                curPosition += tempSourceBytesLen;
            }
            decodeStrResult = new String(decodeResultBytes, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decodeStrResult;
    }

    /**
     * 私钥解密
     *
     * @param sourceBase64RSA
     * @return
     */
    public static String decode(String sourceBase64RSA) {
        return decode(sourceBase64RSA, privateKey);
    }

    public static void main(String[] args) {
        String username = encode("123456");
        String password = encode("123456");
        System.out.println("加密userName:[" + username+"]"+"password:["+password+"]");
    }

} 

2、自定义注解;

package com.inter.my;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//作用于方法上,也可以作用于类上
@Target(ElementType.METHOD)
//作用域为运行时有效
@Retention(RetentionPolicy.RUNTIME)
public @interface YinXing {
    /**
    * 加密解密标识 
    * 默认加密
    * true:加密;false:不加密
    ** /
    boolean encry() default true ;
}

3、AOP切面;

import com.inter.my.YinXing;
import com.inter.util.RSAUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.UUID;

/**
 * @author yinxing
 * @date 2022-09-08
 */
@Aspect
@Slf4j
@Component
public class UserAspect {

    @Around("@annotation(yinXing)")
    public Object around(ProceedingJoinPoint point, YinXing yinXing) throws Throwable {

        //通过切入点获取目标class对象
        Class<?> aClass = point.getTarget().getClass();
        //获取接入点的类名
        String className = aClass.getName();
        //获取目标方法名称
        String methodName = point.getSignature().getName();
        //获取MyLog注解的value参数
        boolean encry = yinXing.encry();
        if (encry) {
            //拿到方法的入参
            Object[] args = point.getArgs();
            StringBuffer stringBuffer = new StringBuffer();
            log.info("\n===解密前===UserAspect," +
                    "类名[{}]," +
                    "方法名[{}]" +
                    "注解值:[{}]" +
                    "参数:[{}]", className, methodName, encry, args);
            for (int i = 0; i < args.length; i++) {
                Map<String, Object> argMap = (Map<String, Object>) args[i];
                for (Map.Entry<String, Object> entry : argMap.entrySet()) {
                    argMap.put(entry.getKey(), RSAUtils.decode(entry.getValue().toString()));
                }
                args[i] = argMap;
            }
            UUID uuid = UUID.randomUUID();
            log.info("\n===解密后===UserAspect-{}," +
                    "类名[{}]," +
                    "方法名[{}]" +
                    "注解值:[{}]" +
                    "参数:[{}]", uuid, className, methodName, encry, args);
            long startTime = System.currentTimeMillis();
            //运行目标方法
            Object proceed = point.proceed(args);
            long endTime = System.currentTimeMillis();
            log.info("\n===返回的参数加密前===UserAspect-{}," +
                    "类名[{}]," +
                    "方法名[{}]" +
                    "注解值:[{}]" +
                    "耗时:[{}ms]" +
                    "返回参数:[{}]", uuid, className, methodName, encry, endTime - startTime, proceed.toString());
            Map<String, Object> proceedMap = (Map<String, Object>) proceed;
            for (Map.Entry<String, Object> entry : proceedMap.entrySet()) {
                proceedMap.put(entry.getKey(), RSAUtils.encode(entry.getValue().toString()));
            }
            log.info("\n===返回的参数加密后===UserAspect-{}," +
                    "类名[{}]," +
                    "方法名[{}]" +
                    "注解值:[{}]" +
                    "耗时:[{}ms]" +
                    "返回参数:[{}]", uuid, className, methodName, encry, endTime - startTime, proceedMap);
            return proceedMap;
        } else {
            Object proceed = point.proceed();
            return proceed;
        }
    }
}


4、实现效果。

4.1不加密效果展示

在这里插入图片描述

4.2加密效果展示

在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值