IAesSecureService
public interface IAesSecureService {
/** 加密 **/
String AESEncryption(String encryptString) throws Exception;
/** 解密 **/
String AESDecryption(String decryptString) throws Exception;
}
AesSecureServiceImpl
@Service
public class AesSecureServiceImpl implements IAesSecureService{
/** 32位 **/
private static String SECRET_KEY = "***32位***";
/** 偏移量字符串16位 当模式是CBC的时候必须设置偏移量 **/
private static String iv = "***16位***";
private static String Algorithm = "AES";
/** 算法/模式/补码方式 **/
private static String AlgorithmProvider = "AES/CBC/PKCS5Padding";
@Override
public String AESEncryption(String encryptString) throws Exception {
byte[] bytes = SECRET_KEY.getBytes("utf-8");
String AESContent = Hex.encodeHexString(encrypt(encryptString, bytes));
return AESContent;
}
@Override
public String AESDecryption(String decryptString) throws Exception {
byte[] bytes = SECRET_KEY.getBytes("utf-8");
String AESContent = new String(decrypt(decryptString, bytes));
return AESContent;
}
public static byte[] encrypt(String src, byte[] key) throws Exception {
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
IvParameterSpec ivParameterSpec = getIv();
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] cipherBytes = cipher.doFinal(src.getBytes(Charset.forName("utf-8")));
return cipherBytes;
}
public static byte[] decrypt(String src, byte[] key) throws Exception {
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
IvParameterSpec ivParameterSpec = getIv();
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] plainBytes = cipher.doFinal(Hex.decodeHex(src));
return plainBytes;
}
public static IvParameterSpec getIv() throws Exception {
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8"));
return ivParameterSpec;
}
}
Secret
@Target({ElementType.TYPE,ElementType.METHOD}) //可以作用在类和方法上
@Retention(RetentionPolicy.RUNTIME) //运行时起作用
public @interface Secret {
// 参数类(用来传递加密数据,只有方法参数中有此类或此类的子类才会执行加解密)
Class value();
// 参数类中传递加密数据的属性名,默认encryptStr
String encryptStrName() default "encryptStr";
}
BaseVO
//基类
@Data
public class BaseVO {
//加密密文
private String encryptStr;
}
ActApiSecretAop
@Component
@Aspect
@Slf4j
public class ActApiSecretAop {
@Autowired
IAesSecureService aesSecureService;
/** 是否进行加密解密,通过配置文件注入(不配置默认为true) **/
@Value("${isSecret}")
boolean isSecret;
/** 定义切点,使用@Secret注解的类或方法 **/
@Pointcut("@within(com.util.secret.safe.Secret) || @annotation(com.util.secret.safe.Secret)")
public void pointCut(){}
/** 环绕通知 **/
@Around("pointCut()")
public ResponseVO around(ProceedingJoinPoint point) throws Throwable {
ResponseVO result = null;
// 获取被代理方法参数
Object[] args = point.getArgs();
// 获取被代理对象
Object target = point.getTarget();
// 获取通知签名
MethodSignature signature = (MethodSignature)point.getSignature();
// 获取被代理方法
Method pointMethod = target.getClass().getMethod(signature.getName(), signature.getParameterTypes());
// 获取被代理方法上面的注解@Secret
Secret secret = pointMethod.getAnnotation(Secret.class);
// 被代理方法上没有,则说明@Secret注解在被代理类上
if(secret==null){
secret = target.getClass().getAnnotation(Secret.class);
}
if(secret!=null){
// 获取注解上声明的加解密类
Class clazz = secret.value();
// 获取注解上声明的加密参数名
String encryptStrName = secret.encryptStrName();
for (int i = 0; i < args.length; i++) {
// 如果是clazz类型则说明使用了加密字符串encryptStr传递的加密参数
if(clazz.isInstance(args[i])){
//将args[i]转换为clazz表示的类对象
Object cast = clazz.cast(args[i]);
// 通过反射,执行getEncryptStr()方法,获取加密数据
Method method = clazz.getMethod(getMethodName(encryptStrName));
// 执行方法,获取加密数据
String encryptStr = (String) method.invoke(cast);
// 加密字符串是否为空
if(StringUtils.isNotBlank(encryptStr)){
// 解密
String json = aesSecureService.AESDecryption(encryptStr);
// 转换vo
args[i] = JSON.parseObject(json, (Type) args[i].getClass());
}
}
// 其他类型,比如基本数据类型、包装类型就不使用加密解密了
}
}
// 执行请求
result = (ResponseVO) point.proceed(args);
// 判断配置是否需要返回加密
if(isSecret){
// 获取返回值json字符串
String jsonString = JSON.toJSONString(result.getBody());
// 加密
String s = aesSecureService.AESEncryption(jsonString);
result.setBody(s);
}
return result;
}
// 转化方法名
private String getMethodName(String name){
String first = name.substring(0,1);
String last = name.substring(1);
first = StringUtils.upperCase(first);
return "get" + first + last;
}
}
使用
方法或者类上加:@Secret(BaseVO.class)
application.yml/properties加上:
# 配置是否开启AOP参数加密解密,不配置默认为true
isSecret: true