因为项目需要,需要对请求数据数据和返回数据统一做加解密的处理。本文重点介绍一下,在过滤器中修改请求数据和返回数据,不详细介绍加解密的实现。
原理
如上图所示,输出流并不像我们想象的那样,必经过滤器,然后返回给客户端,这样就会有一个问题,当我们在过滤器对返回数据做处理,然后写到客户端时,此时可能输出流已经被相应到客户端了。下图是我们要实现的效果。
使用自己包装好的repsonse,以达到sevlet直接向客户端返回数据失效的效果。这样我们就可以在过滤器中,对我们的请求数据和返回数据进行处理,使之完全在我们的控制范围内。
源码
public class AESFilter implements Filter {
private final Logger LOG = LoggerFactory.getLogger(AESFilter.class);
/**
* aes 密匙
*/
@Value(“
fpfkxt.aes.key”)privateStringAESKEY;/∗∗∗是否启用AES加解密请求标志∗/@Value(“
{sfqyaes}”)
private String SFQYAES;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 如果启用aes加密解密
if (CommonConst.SFQYAES_Y.equals(SFQYAES)) {
String requestBody = getRequestBody((HttpServletRequest) request);
//解密请求报文
String requestBodyMw = CryptionUtil.aesDecrypt(requestBody.trim(),
AES_KEY);
LOG.debug("解密请求数据:" + requestBodyMw);
WrapperedResponse wrapResponse = new WrapperedResponse(
(HttpServletResponse) response);
WrapperedRequest wrapRequest = new WrapperedRequest(
(HttpServletRequest) request, requestBodyMw);
chain.doFilter(wrapRequest, wrapResponse);
byte[] data = wrapResponse.getResponseData();
LOG.debug("原始返回数据: " + new String(data, "utf-8"));
// 加密返回报文
String responseBodyMw = CryptionUtil.aesEncrypt(data, AES_KEY);
LOG.debug("加密返回数据: " + responseBodyMw);
writeResponse(response, responseBodyMw);
} else {
chain.doFilter(request, response);
}
}
private void writeResponse(ServletResponse response, String responseString)
throws IOException {
PrintWriter out = response.getWriter();
out.print(responseString);
out.flush();
out.close();
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @param req
* @return
*/
private String getRequestBody(HttpServletRequest req) {
try {
BufferedReader reader = req.getReader();
StringBuffer sb = new StringBuffer();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String json = sb.toString();
return json;
} catch (IOException e) {
LOG.error("验签时请求体读取失败", e);
}
return "";
}
}
public class WrapperedRequest extends HttpServletRequestWrapper {
/**
* 请求报文
*/
private String requestBody = null;
HttpServletRequest req = null;
public WrapperedRequest(HttpServletRequest request) {
super(request);
this.req = request;
}
public WrapperedRequest(HttpServletRequest request, String requestBody) {
super(request);
this.requestBody = requestBody;
this.req = request;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.ServletRequestWrapper#getReader()
*/
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new StringReader(requestBody));
}
/*
* (non-Javadoc)
*
* @see javax.servlet.ServletRequestWrapper#getInputStream()
*/
@Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStream() {
private InputStream in = new ByteArrayInputStream(
requestBody.getBytes(req.getCharacterEncoding()));
@Override
public int read() throws IOException {
return in.read();
}
};
}
}
public class WrapperedResponse extends HttpServletResponseWrapper {
private ByteArrayOutputStream buffer = null;
private ServletOutputStream out = null;
private PrintWriter writer = null;
public WrapperedResponse(HttpServletResponse resp) throws IOException {
super(resp);
buffer = new ByteArrayOutputStream();// 真正存储数据的流
out = new WapperedOutputStream(buffer);
writer = new PrintWriter(new OutputStreamWriter(buffer,
this.getCharacterEncoding()));
}
/** 重载父类获取outputstream的方法 */
@Override
public ServletOutputStream getOutputStream() throws IOException {
return out;
}
/** 重载父类获取writer的方法 */
@Override
public PrintWriter getWriter() throws UnsupportedEncodingException {
return writer;
}
/** 重载父类获取flushBuffer的方法 */
@Override
public void flushBuffer() throws IOException {
if (out != null) {
out.flush();
}
if (writer != null) {
writer.flush();
}
}
@Override
public void reset() {
buffer.reset();
}
/** 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 */
public byte[] getResponseData() throws IOException {
flushBuffer();
return buffer.toByteArray();
}
/** 内部类,对ServletOutputStream进行包装 */
private class WapperedOutputStream extends ServletOutputStream {
private ByteArrayOutputStream bos = null;
public WapperedOutputStream(ByteArrayOutputStream stream)
throws IOException {
bos = stream;
}
@Override
public void write(int b) throws IOException {
bos.write(b);
}
@Override
public void write(byte[] b) throws IOException {
bos.write(b, 0, b.length);
}
}
}