接口加解密(主要实现分为 请求参数解密,返回参数加密 两个操作)
玩一下, 开搞,开搞!!!
实现思路
首先加解密用的就是各种加密算法进行处理的,之前我也发过多种加密方式的工具类(Java加密算法工具类(AES、DES、MD5、RSA)),其次就是用aop拦截处理,可以用自定义注解的形式定义是加密还是解密以及何种加解密方式,然后判断逻辑后在执行目标前后进行处理。aop拦截还有多种拦截方式我之前也有写过(JAVA三种拦截方式),可以参考下。
引入maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
核心代码
自定义注解
其实这两个注解是可以合成一个使用的,这边为了对比明显
/**
* 加密类型枚举
* (对应工具类中各个加解密类型)
*/
public enum EncryptType {
AES,
DES,
MD5,
RSA,
NULL
}
import com.zhangximing.springboot_annotate.util.EncryptType;
import java.lang.annotation.*;
/**
* @Author: zhangximing
* @Email: 530659058@qq.com
* @Date: 2024/4/6 10:28
* @Description: 自定义加密
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CustomEncryption {
//加密类型
EncryptType type() default EncryptType.NULL;
}
import com.zhangximing.springboot_annotate.util.EncryptType;
import java.lang.annotation.*;
/**
* @Author: zhangximing
* @Email: 530659058@qq.com
* @Date: 2024/4/6 10:29
* @Description: 自定义解密
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CustomDecryption {
//解密类型
EncryptType type() default EncryptType.NULL;
}
AOP切面
注意算法部分参考之前(Java加密算法工具类(AES、DES、MD5、RSA))
import com.alibaba.fastjson.JSONObject;
import com.zhangximing.springboot_annotate.util.AESUtil;
import com.zhangximing.springboot_annotate.util.MD5Util;
import com.zhangximing.springboot_annotate.util.RSAUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* @Author: zhangximing
* @Email: 530659058@qq.com
* @Date: 2024/4/6 10:44
* @Description: 加解密切面
*/
@Aspect
@Configuration
public class SecurityInterceptor {
// 拦截用过加密注释的
@Pointcut("@annotation(com.zhangximing.springboot_annotate.annotate.CustomEncryption)")
public void encPointCut(){
}
// 拦截用过解密注释的
@Pointcut("@annotation(com.zhangximing.springboot_annotate.annotate.CustomDecryption)")
public void decPointCut(){
}
@Around("decPointCut() || encPointCut()")
public Object AroundCustomDecryption(ProceedingJoinPoint point){
// 前置逻辑
Object result = null;
//获得当前访问的class
Class<?> className = point.getTarget().getClass();
//获得访问的方法名
String methodName = point.getSignature().getName();
//得到方法的参数的类型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// HttpServletRequest request = attributes.getRequest();
//入参
Object[] args = point.getArgs();
JSONObject param = null;
if (args != null && args.length > 0){
param = JSONObject.parseObject(args[0].toString());
}
Method method = null;
//解密
try {
// 得到访问的方法对象
method = className.getMethod(methodName, argClass);
// 判断是否存在@CustomDecryption
if (method.isAnnotationPresent(CustomDecryption.class) && param != null){
CustomDecryption customDecryption = method.getAnnotation(CustomDecryption.class);
System.out.println("使用算法:" + customDecryption.type());
// 解密数据
String encryptData = param.getString("encryptData");
if (null == encryptData || "".equals(encryptData)){
throw new RuntimeException("param error,encryptData is null");
}
String decryptData = "";
System.out.println("解密前的数据:"+ encryptData);
switch (customDecryption.type()){
case AES:
byte[] decrypted = AESUtil.decryptECB(AESUtil.key128, Base64.getDecoder().decode(encryptData));
decryptData = new String(decrypted, StandardCharsets.UTF_8);
break;
case DES:
//jdk8才有sun.misc,这里不做展示
break;
case MD5:
//md5不支持解密
throw new RuntimeException("md5 decrypt error");
// break;
case RSA:
byte[] bytes = RSAUtil.decryptPrivateKey(Base64.getDecoder().decode(encryptData), RSAUtil.getRsaPrivateKey);
decryptData = new String(bytes);
break;
default:
break;
}
System.out.println("解密后的数据:"+ decryptData);
param.put("decryptData", decryptData);
//替换请求入参
args[0] = param;
}
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
// 执行目标方法
try {
result = point.proceed(args);
} catch (Throwable e) {
e.printStackTrace();
return e.getMessage();
}
//加密
try {
// 判断是否存在@CustomEncryption
if (method.isAnnotationPresent(CustomEncryption.class) && result != null){
CustomEncryption customEncryption = method.getAnnotation(CustomEncryption.class);
System.out.println("使用算法:" + customEncryption.type());
String encryptData = "";
System.out.println("加密前的数据:"+ result);
String beforeResult = JSONObject.toJSONString(result);
if (beforeResult.length() > 2){
beforeResult = beforeResult.substring(1, beforeResult.length() - 1);
beforeResult = beforeResult.replaceAll("\\\\", "");
}
System.out.println("加密前处理的数据:"+ beforeResult);
switch (customEncryption.type()){
case AES:
byte[] decrypted = AESUtil.encryptECB(AESUtil.key128, beforeResult.getBytes(StandardCharsets.UTF_8));
encryptData = Base64.getEncoder().encodeToString(decrypted);
break;
case DES:
//jdk8才有sun.misc,这里不做展示
break;
case MD5:
encryptData = MD5Util.getMd5(beforeResult);
break;
case RSA:
byte[] bytes = RSAUtil.encryptPublicKey(beforeResult.getBytes(), RSAUtil.getRsaPublicKey);
encryptData = Base64.getEncoder().encodeToString(bytes);
break;
default:
break;
}
JSONObject resultJson = new JSONObject();
System.out.println("加密后的数据:"+ encryptData);
resultJson.put("encryptData",encryptData);
result = resultJson.toJSONString();
}
}catch (Exception e){
e.printStackTrace();
return e.getMessage();
}
return result;
}
}
测试方法
import com.alibaba.fastjson.JSONObject;
import com.zhangximing.springboot_annotate.annotate.CustomDecryption;
import com.zhangximing.springboot_annotate.annotate.CustomEncryption;
import com.zhangximing.springboot_annotate.util.EncryptType;
import org.springframework.web.bind.annotation.*;
/**
* 测试接口加解密
*/
@RestController
@RequestMapping("/security")
public class SecurityController {
//解密测试
@CustomDecryption(type = EncryptType.RSA)
@RequestMapping("/decrypt")
public String decrypt(@RequestBody JSONObject param) {
return param.toJSONString();
}
//加密测试
@CustomEncryption(type = EncryptType.RSA)
@RequestMapping("/encrypt")
public String encrypt(@RequestBody JSONObject param) {
param.put("success","ok");
return param.toJSONString();
}
}
测试结果
接口加密(可以看到返回了加密后的字符串)
接口解密(可以看到返回了加解密后的字符串)
控制台打印(统一设置了RSA算法)