AOP实现加解密(二)

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值