Spring统一请求Post报文解密

目录

目录

背景

技术难点

实现方案

具体实现

自定义一个HttpServletRequestWrapper

解密拦截器

总结

使用场景


背景

        在一个请求报文中,所有的参数需要加密;并且数据在传输的报文中要做数据签名;我们在数据传输中使用的报文使用的请求为Post。

技术难点

Post数据流在请求中不能重复读取。在Filter中读取了请求体的数据后,在后面的处理器读取的数据流中获取不到数据流。

实现方案

通过重新自定义一个HttpServletRequestWrapper数据流,实现数据流的可重复读取。定义前台传加密公钥为:pk;加密数据为:data;数据签名为:sign

具体实现

自定义一个HttpServletRequestWrapper

package com.filter;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Base64;

public class WapperRequestWrapper extends  HttpServletRequestWrapper {

    private static final Logger log = LoggerFactory.getLogger(WapperRequestWrapper.class);

    private final byte[] body;
    //公钥
    private String key;
    //加密数据
    private String data;
    //数据签名
    private String sign;

    public WapperRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        byte[] bytes = this.getBodyContent(request).getBytes(Charset.forName("UTF-8"));
        String json = new String(bytes);
        JSONObject jsonObject = JSONObject.parseObject(json);
        this.key= jsonObject.getString("pk");
        this.data= jsonObject.getString("data");
        this.sign = jsonObject.getString("sign");
        //数据解密后的
        // deCodeData  解密后的字符串

        body = deCodeData.getBytes();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream bais = new ByteArrayInputStream(body);

        return new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }
    public static String getBodyContent(HttpServletRequest request) throws IOException {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
             inputStream = request.getInputStream();
             reader = new BufferedReader( new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            inputStream.close();
            reader.close();
        }
        return sb.toString();
    }

}

通过自己实现可以重复读取Post中Body的数据。

解密拦截器

package com.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.swagger.models.auth.In;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.RequestMethod;
import sun.nio.cs.UnicodeEncoder;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/**
* @ClassName: DeCodeFilter 
* @Description: 
* @author yangchao.cool@gmail.com
* @date 2021/9/13 16:23
*/
@WebFilter(filterName = "decodeFilter", urlPatterns = "/*")
@Order(1)
public class DeCodeFilter implements Filter {

    Logger logger = LoggerFactory.getLogger(getClass());


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       ServletRequest requestWrapper = null;
            HttpServletRequest request1 = (HttpServletRequest) request;
            String method = request1.getMethod();
            boolean hasPost = RequestMethod.POST.name().equals(method);
            if (request instanceof HttpServletRequest && hasPost) {
                requestWrapper = new WapperRequestWrapper(request1);
            }
            //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
            // 在chain.doFiler方法中传递新的request对象

            if (hasPost && !Objects.isNull(requestWrapper)) {
                chain.doFilter(requestWrapper, response);
            } else {
                chain.doFilter(request, response);
            }
    }

    @Override
    public void destroy() {
    }
}

总结

主要通过重新数据流,把数据流读取出来并放到内存中,实现多次数据流读取,虽然多开辟了内存,但是完成数据流多次读取,同时可以实现公共请求报文置入与处理

使用场景

1、请求解密

2、公共用户信息验证与用户数据植入

3、数据统一验证

4、等等

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值