自定义注解解决Controller接收的参数自动解密

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

        在日常开发工作中,我们难免会对接其他系统平台api,那么平台间的参数传输为了保证数据安全,双方都会根据提前约定好的密钥进行加解密,来保证数据在网络传输间的安全性,防止出现数据泄露的安全风险。

        话不多说让我们直接进入正题。

一、定义注解

        先创建一个注解类,并且在该注解类上添加@Retention和@Target注解,前者表示该注解在程序运行时可生效,后者表示这个注解可以应用在字段(成员变量)上、方法参数上。后续我们需要对哪些参数进行解密操作,那么就在该参数上加上此注解,作为标识。

/**
 * 解密注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface Decrypted {
}

二、使用步骤

1.编写具体实现逻辑

        接下来我们需要编写对于注解标识的进一步处理,通过继承RequestBodyAdvice这个类,该类是Spring Framework 中的一个接口,它属于 Spring MVC 模块,用于在处理请求体(Request Body)数据之前进行自定义处理。具体来说,RequestBodyAdvice 提供了在请求体数据被绑定到方法参数之前,以及响应体数据被写回客户端之前进行处理的扩展点。

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.openservices.shade.org.apache.commons.lang3.StringEscapeUtils;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@RestControllerAdvice
@RefreshScope
public class DecryptedModelAttributeResolver implements RequestBodyAdvice {

    
    private String privateKey;

    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return methodParameter.hasParameterAnnotation(Decrypted.class) && methodParameter.hasParameterAnnotation(RequestBody.class);
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        Annotation[] parameterAnnotations = methodParameter.getParameterAnnotations();
        Object argument = methodParameter.getParameterType();
        Field[] superFields = argument.getClass().getSuperclass().getDeclaredFields();
        for (Annotation annotation : parameterAnnotations) {
            if (annotation.annotationType() == Decrypted.class) {
                //TODO
                return httpInputMessage;
            }
        }
        return httpInputMessage;
    }

    @SneakyThrows
    @Override
    public Object afterBodyRead(Object object, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        BaseRequest baseRequest = (BaseRequest) object;
        String data = baseRequest.getData();
        if (StringUtils.isEmpty(data)) {

        } else {
            //解密成对应的对象
            String decryptData = AESUtils.AESDecryptDemo(data, privateKey);
            return JSONUtil.toBean(StringEscapeUtils.unescapeJava(decryptData), object.getClass());
        }
        //获取data
        return object;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }
}

         我们继承该类后需要实现4个方法:

  • supports方法用于确定是否应该应用当前 RequestBodyAdvice实现。返回true表示应该应用,返回false表示不应用。我们在这里判断了参数前是否同时具有注解@Decrypted和注解@RequestBody,有的话返回true,没有的话返回false,也即只对加了注解的参数进行解密操作。
  • beforeBodyRead方法在请求体数据被绑定到 Controller 方法参数之前被调用,可以在这里对请求体数据进行预处理或修改。
  • afterBodyRead方法在请求体数据被绑定到 Controller 方法参数之后被调用,可以在这里对方法参数的数据进行进一步处理。即我们在这里对收到的请求参数对象中data数据,进行一个判空并且进行解密操作,解密后将数据从String装为原数据格式,并且最后进行返回。
  • handleEmptyBody方法在请求体为空时被调用,可以在这里处理空请求体的情况。
@PostMapping("/order/crete")
    public BaseResult orderCreate(@RequestBody @Decrypted OrderCreateRequest request) {
        return orderService.orderCreate(request);
    }

         如代码所示,我们讲两个注解加在请求参数对象前,那么在项目启动后,接收到发送来的请求后,就会走上边的处理逻辑,对于接受到的request参数进行一个解密操作,并且把解密后的数据重新封装返回,接着再会把解密后的request传入到service中进行业务逻辑处理。


总结

        以上就是一个简单的自定义注解去解密Controller层接收到的请求参数,而这也只是其中的一个类型的应用,还可以继续进行自定义扩展编写,不仅限于在参数上,也可以通过自己实际的需求,去选择合适的注解,灵活的使用自定义注解式开发可以很好的帮助我们在日常工作中省去很多繁琐的开发步骤,也是一个提升我们自身编码能力与代码思维扩散的过程,最后谢谢大家的观看、点赞、收藏。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值