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
    评论
好的,针对您的问题,我可以给您一些简单的解释。 SpringBoot中的AOP(面向切面编程)可以帮助我们对方法进行拦截和增强,这样我们就可以在方法执行前后进行一些自己想要的操作,比如接口的请求数据解密和返回数据加密。 具体来说,我们可以通过定义一个切面类,在其中定义一个前置通知和一个后置通知。前置通知可以在方法执行前进行解密操作,后置通知可以在方法执行后进行加密操作。 下面是一个简单的示例代码: ```java @Aspect @Component public class EncryptAspect { @Autowired private EncryptService encryptService; @Pointcut("execution(public * com.example.controller.*.*(..))") public void encrypt() {} @Before("encrypt()") public void doEncrypt(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); for (Object arg : args) { if (arg instanceof String) { String decrypted = encryptService.decrypt((String) arg); // 将解密后的数据重新设置到参数中 // ... } } } @AfterReturning(value = "encrypt()", returning = "result") public void doDecrypt(JoinPoint joinPoint, Object result) { if (result instanceof String) { String encrypted = encryptService.encrypt((String) result); // 将加密后的数据返回 // ... } } } ``` 在上面的示例代码中,我们定义了一个切面类`EncryptAspect`,其中通过`@Pointcut`注解定义了需要拦截的方法,即`com.example.controller`包下的所有方法。在`doEncrypt`方法中,我们可以获取到方法的参数,并进行解密操作;在`doDecrypt`方法中,我们可以获取到方法的返回值,并进行加密操作。 需要注意的是,上面的示例代码中的`EncryptService`是一个加解密服务的接口,具体的加解密实现可以根据自己的需求进行编写。 希望以上解释可以帮助到您。如果还有其他问题,欢迎随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值