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加密效果展示

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

被折叠的 条评论
为什么被折叠?



