目录
目录
自定义一个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、等等