我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么用注解+RequestBodyAdvice实现http请求内容加解密方式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么用注解+RequestBodyAdvice实现http请求内容加解密方式

这篇文章主要介绍“怎么用注解+RequestBodyAdvice实现http请求内容加解密方式”,在日常操作中,相信很多人在怎么用注解+RequestBodyAdvice实现http请求内容加解密方式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么用注解+RequestBodyAdvice实现http请求内容加解密方式”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

注解主要用来指定那些需要加解密的controller方法

实现比较简单

@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface SecretAnnotation {    boolean encode() default false;    boolean decode() default false;}

使用时添加注解在controller的方法上

@PostMapping("/preview")    @SecretAnnotation(decode = true)    public ResponseVO<ContractSignVO> previewContract(@RequestBody FillContractDTO fillContractDTO)  {        return contractSignService.previewContract(fillContractDTO);    }

请求数据由二进制流转为类对象数据,对于加密过的数据,需要在二进制流被处理之前进行解密,否则在转为类对象时会因为数据格式不匹配而报错。

因此使用RequestBodyAdvice的beforeBodyRead方法来处理。

@Slf4j@RestControllerAdvicepublic class MyRequestControllerAdvice implements RequestBodyAdvice {    @Override    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {        return methodParameter.hasParameterAnnotation(RequestBody.class);    }    @Override    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {        return o;    }    @Autowired    private MySecretUtil mySecretUtil;    @Override    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {        if (methodParameter.getMethod().isAnnotationPresent(SecretAnnotation.class)) {            SecretAnnotation secretAnnotation = methodParameter.getMethod().getAnnotation(SecretAnnotation.class);            if (secretAnnotation.decode()) {                return new HttpInputMessage() {                    @Override                    public InputStream getBody() throws IOException {                        List<String> appIdList = httpInputMessage.getHeaders().get("appId");                        if (appIdList.isEmpty()){                            throw new RuntimeException("请求头缺少appID");                        }                        String appId = appIdList.get(0);                        String bodyStr = IOUtils.toString(httpInputMessage.getBody(),"utf-8");                        bodyStr = mySecretUtil.decode(bodyStr,appId);                        return  IOUtils.toInputStream(bodyStr,"utf-8");                    }                    @Override                    public HttpHeaders getHeaders() {                        return httpInputMessage.getHeaders();                    }                };            }        }        return httpInputMessage;    }    @Override    public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {        return o;    }}

mySecretUtil.decode(bodyStr,appId)的内容是,通过请求头中的AppID去数据库中查找对于的秘钥,之后进行解密,返回解密后的字符串。

再通过common.io包中提供的工具类IOUtils将字符串转为inputstream流,替换HttpInputMessage,返回一个body数据为解密后的二进制流的HttpInputMessage。

Stringboot RequestBodyAdvice接口如何实现请求响应加解密

在实际项目中,我们常常需要在请求前后进行一些操作,比如:参数解密/返回结果加密,打印请求参数和返回结果的日志等。这些与业务无关的东西,我们不希望写在controller方法中,造成代码重复可读性变差。这里,我们讲讲使用@ControllerAdvice和RequestBodyAdvice、ResponseBodyAdvice来对请求前后进行处理(本质上就是AOP),来实现日志记录每一个请求的参数和返回结果。

1.加解密工具类

package com.linkus.common.utils;import java.security.Key;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.Security;import javax.annotation.PostConstruct;import javax.crypto.Cipher;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.util.encoders.Hex;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;@Componentpublic class Aes {        private String sessionKey="加解密密钥";    // 偏移量 16位    private static  String iv="偏移量";    // 算法名称    final String KEY_ALGORITHM = "AES";    // 加解密算法/模式/填充方式    final String algorithmStr = "AES/CBC/PKCS7Padding";    // 加解密 密钥 16位    byte[] ivByte;    byte[] keybytes;    private Key key;    private Cipher cipher;    boolean isInited = false;    public void init() {        // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要        keybytes = iv.getBytes();        ivByte = iv.getBytes();        Security.addProvider(new BouncyCastleProvider());        // 转化成JAVA的密钥格式        key = new SecretKeySpec(keybytes, KEY_ALGORITHM);        try {            // 初始化cipher            cipher = Cipher.getInstance(algorithmStr, "BC");        } catch (NoSuchAlgorithmException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (NoSuchPaddingException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (NoSuchProviderException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }        public String encrypt(String content) {        byte[] encryptedText = null;        byte[] contentByte = content.getBytes();        init();        try {            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivByte));            encryptedText = cipher.doFinal(contentByte);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return new String(Hex.encode(encryptedText));    }        public String decrypt(String encryptedData) {        byte[] encryptedText = null;        byte[] encryptedDataByte = Hex.decode(encryptedData);        init();        try {            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivByte));            encryptedText = cipher.doFinal(encryptedDataByte);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return new String(encryptedText);    }    public static void main(String[] args) {        Aes aes = new Aes();        String a="{\n" +                "\"distance\":\"1000\",\n" +                "\"longitude\":\"28.206471\",\n" +                "\"latitude\":\"112.941301\"\n" +                "}";        //加密字符串        //String content = "孟飞快跑";        // System.out.println("加密前的:" + content);//        System.out.println("加密密钥:" + new String(keybytes));        // 加密方法        String enc = aes.encrypt(a);        System.out.println("加密后的内容:" + enc);        String dec="";        // 解密方法        try {            dec = aes.decrypt(enc);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println("解密后的内容:" + dec);    }}

2.请求解密

前端页面传过来的是密文,我们需要在Controller获取请求之前对密文解密然后传给Controller

package com.linkus.common.filter;import com.alibaba.fastjson.JSON;import com.linkus.common.constant.KPlatResponseCode;import com.linkus.common.exception.CustomException;import com.linkus.common.exception.JTransException;import com.linkus.common.service.util.MyHttpInputMessage;import com.linkus.common.utils.Aes;import com.linkus.common.utils.http.HttpHelper;import lombok.extern.slf4j.Slf4j;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.MethodParameter;import org.springframework.http.HttpInputMessage;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.lang.Nullable;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;import javax.servlet.http.HttpServletRequest;import java.io.*;import java.lang.reflect.Type;@Component//可以配置指定需要解密的包,支持多个@ControllerAdvice(basePackages = {"com.linkus.project"})@Slf4jpublic class DecryptRequestBodyAdvice implements RequestBodyAdvice {    Logger log = LoggerFactory.getLogger(getClass());    Aes aes=new Aes();    @Override    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {    //true开启功能,false关闭这个功能        return true;    }//在读取请求之前做处理    @Override    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> selectedConverterType) throws IOException {        //获取请求数据        String string = "";        BufferedReader bufferedReader = null;        InputStream inputStream = inputMessage.getBody();            //这个request其实就是入参 可以从这里获取流            //入参放在HttpInputMessage里面  这个方法的返回值也是HttpInputMessage            try {            string=getRequestBodyStr(inputStream,bufferedReader);        } finally {            if (bufferedReader != null) {                try {                    bufferedReader.close();                } catch (IOException ex) {                    throw ex;                }            }        }                String decode = null;        if(HttpHelper.isEncrypted(inputMessage.getHeaders())){        try {            //            //解密操作            //Map<String,String> dataMap = (Map)body;            //log.info("接收到原始请求数据={}", string);            // inputData 为待加解密的数据源//解密            decode= aes.decrypt(string);            //log.info("解密后数据={}",decode);        } catch (Exception e ) {            log.error("加解密错误:",e);           throw  new CustomException(KPlatResponseCode.MSG_DECRYPT_TIMEOUT,KPlatResponseCode.CD_DECRYPT_TIMEOUT);        }        //把数据放到我们封装的对象中        }else{            decode = string;        }       // log.info("接收到请求数据={}", decode);//        log.info("接口请求地址{}",((HttpServletRequest)inputMessage).getRequestURI());        return new MyHttpInputMessage(inputMessage.getHeaders(), new ByteArrayInputStream(decode.getBytes("UTF-8")));    }    @Override    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {        return body;    }    @Override    public Object handleEmptyBody(@Nullable Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5) {        return var1;    }//自己写的方法,不是接口的方法,处理密文    public String getRequestBodyStr( InputStream inputStream,BufferedReader bufferedReader) throws IOException {        StringBuilder stringBuilder = new StringBuilder();            if (inputStream != null) {                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));                char[] charBuffer = new char[128];                int bytesRead = -1;                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {                    stringBuilder.append(charBuffer, 0, bytesRead);                }            } else {                stringBuilder.append("");            }        String string = stringBuilder.toString();        return string;    }}

3.响应加密

将返给前端的响应加密,保证数据的安全性

package com.linkus.common.filter;import com.alibaba.fastjson.JSON;import com.linkus.common.utils.Aes;import com.linkus.common.utils.DesUtil;import com.linkus.common.utils.http.HttpHelper;import io.swagger.models.auth.In;import lombok.experimental.Helper;import lombok.extern.slf4j.Slf4j;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.MethodParameter;import org.springframework.http.MediaType;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@Component@ControllerAdvice(basePackages = {"com.linkus.project"})@Slf4jpublic class EncryResponseBodyAdvice implements ResponseBodyAdvice<Object> {    Logger log = LoggerFactory.getLogger(getClass());    Aes aes=new Aes();    @Override    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {        return true;    }        @Override    public Object beforeBodyWrite(Object obj, MethodParameter returnType, MediaType selectedContentType,                                  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest serverHttpRequest,                                  ServerHttpResponse serverHttpResponse) {        String returnStr = "";        Object retObj = null;        log.info("接口请求地址{}",serverHttpRequest.getURI());        //日志过滤        //retObj=infofilter.getInfoFilter(returnType,obj);        if(HttpHelper.isEncrypted(serverHttpRequest.getHeaders())) {            try {                //添加encry header,告诉前端数据已加密                //serverHttpResponse.getHeaders().add("infoe", "e=a");                //获取请求数据                String class="lazy" data-srcData = JSON.toJSONString(obj);                //加密                returnStr = aes.encrypt(class="lazy" data-srcData).replace("\r\n", "");                //log.info("原始数据={},加密后数据={}", obj, returnStr);                return returnStr;            } catch (Exception e) {                log.error("异常!", e);            }        }        log.info("原始数据={}",JSON.toJSONString(obj));        return obj;    }}

到此,关于“怎么用注解+RequestBodyAdvice实现http请求内容加解密方式”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么用注解+RequestBodyAdvice实现http请求内容加解密方式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么用注解+RequestBodyAdvice实现http请求内容加解密方式

这篇文章主要介绍“怎么用注解+RequestBodyAdvice实现http请求内容加解密方式”,在日常操作中,相信很多人在怎么用注解+RequestBodyAdvice实现http请求内容加解密方式问题上存在疑惑,小编查阅了各式资料,整理
2023-06-20

springboot中如何使用自定义注解实现加解密及脱敏方式

这篇文章主要介绍springboot中如何使用自定义注解实现加解密及脱敏方式,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!自定义注解实现加解密及脱敏定义自定义注解@Documented@Target({Element
2023-06-22

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录