@ResponseBodyAdvice & @RequestBodyAdivce失效

背景

最近项目要有向外部提供服务的能力,但是考虑到数据安全问题,要对接口进行加解密;实现加解密的方案有很多,比如过滤器、拦截器、继承RequestResponseBodyMethodProcessor什么的,不过我最近正在了解@ResponseBodyAdvice @RequestBodyAdvice这俩注解,本着在实践中应用的目的,就准备使用这两个注解来实现加解密功能。
然而,配置好后,请求怎么都进不到这两个注解的类里。摸索了一天的时间,@RestController 和@ResponseBody 都加了,也确认已经扫描进容器中管理了,可就是无法生效。

原因

后来发现项目中之前有对所有的controller进行返回结果的统一包装,使用的是继承RequestResponseBodyMethodProcessor类来实现;
刚刚@ResponseBodyAdvice和@RequestBodyAdvice一直无法生效,就在RequestResponseBodyMethodProcessor这里面做了加密的动作,后来不经意间,把这个类在WebMvcConfigurer中导入的代码注掉了,惊奇的发现@ResponseBodyAdvice @RequestBodyAdvice这俩注解生效了。
所以初步定位 @ResponseBodyAdvice @RequestBodyAdvice 和RequestResponseBodyMethodProcessor 会冲突导致不生效。

解决

RequestResponseBodyMethodProcessor 里的逻辑抽取到@ResponseBodyAdvice里,本来这个也是对返回结果进行增强的,所以放到这里也非常合理。
同时扩展了加密的逻辑。

核心代码


@ControllerAdvice
public class ResponseProcessor implements ResponseBodyAdvice<Object> {
    private ObjectMapper om = new ObjectMapper();
    @Autowired
    EncryptProperties encryptProperties;

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return methodParameter.hasMethodAnnotation(Encrypt.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        byte[] keyBytes = encryptProperties.getKey().getBytes();
        try {
            if(!methodParameter.hasMethodAnnotation(NoResponseWrapperAnnotation.class)){
                body = new ResponseWrapper<>(body);
            }
            body = AESUtils.encrypt(JSONObject.toJSONString(body),encryptProperties.getKey());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return body;
    }
}
```


```java
@ControllerAdvice
public class RequestProcessor extends RequestBodyAdviceAdapter {
    @Autowired
    private EncryptProperties encryptProperties;
    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return methodParameter.hasMethodAnnotation(Decrypt.class) || methodParameter.hasParameterAnnotation(Decrypt.class);
    }

    @Override
    public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        byte[] body = new byte[inputMessage.getBody().available()];
        inputMessage.getBody().read(body);
        try {
            String decrypt = AESUtils.decrypt(new String(body), encryptProperties.getKey());
            final ByteArrayInputStream bais = new ByteArrayInputStream(decrypt.getBytes());
            return new HttpInputMessage() {
                @Override
                public InputStream getBody() throws IOException {
                    return bais;
                }

                @Override
                public HttpHeaders getHeaders() {
                    return inputMessage.getHeaders();
                }
            };
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.beforeBodyRead(inputMessage, parameter, targetType, converterType);
    }
}
```

```java
public class AESUtils {
    private static final String KEY_ALGORITHM = "AES";
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算法

    public static String getKey(int len){
        if(len % 16 != 0){
            System.out.println("长度要为16的整数倍");
            return null;
        }

        char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
        char[] uuid = new char[len];

        if (len > 0) {
            for (int i = 0; i < len; i++) {
                int x = (int) (Math.random() * (len - 0 + 1) + 0);
                uuid[i] = chars[x % chars.length];
            }
        }

        return new String(uuid);
    }


    public static String byteToHexString(byte[] bytes){
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String strHex=Integer.toHexString(bytes[i]);
            if(strHex.length() > 3){
                sb.append(strHex.substring(6));
            } else {
                if(strHex.length() < 2){
                    sb.append("0" + strHex);
                } else {
                    sb.append(strHex);
                }
            }
        }
        return  sb.toString();
    }

    /**
     * AES 加密操作
     *
     * @param content 待加密内容
     * @param key 加密密码
     * @return 返回Base64转码后的加密数据
     */
    public static String encrypt(String content, String key) {
        try {
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器

            byte[] byteContent = content.getBytes("utf-8");

            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));// 初始化为加密模式的密码器

            byte[] result = cipher.doFinal(byteContent);// 加密

            return org.apache.commons.codec.binary.Base64.encodeBase64String(result);//通过Base64转码返回
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * AES 解密操作
     *
     * @param content
     * @param key
     * @return
     */
    public static String decrypt(String content, String key) {

        try {
            //实例化
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

            //使用密钥初始化,设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));

            //执行操作
            byte[] result = cipher.doFinal(org.apache.commons.codec.binary.Base64.decodeBase64(content));

            return new String(result, "utf-8");
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    private static SecretKeySpec getSecretKey(final String key) throws UnsupportedEncodingException {
        //返回生成指定算法密钥生成器的 KeyGenerator 对象
//        KeyGenerator kg = null;

        //            kg = KeyGenerator.getInstance(KEY_ALGORITHM);
//
//            //AES 要求密钥长度为 128
//            kg.init(128, new SecureRandom(key.getBytes()));
//
//            //生成一个密钥
//            SecretKey secretKey = kg.generateKey();

        return new SecretKeySpec(Arrays.copyOf(key.getBytes("utf-8"), 16), KEY_ALGORITHM);// 转换为AES专用密钥

    }
}
```

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值