filter 實現 請求資料與返回資料的加解密
因為專案需要,需要對請求資料資料和返回資料統一做加解密的處理。本文重點介紹一下,在過濾器中修改請求資料和返回資料,不詳細介紹加解密的實現。
原理
如上圖所示,輸出流並不像我們想象的那樣,必經過濾器,然後返回給客戶端,這樣就會有一個問題,當我們在過濾器對返回資料做處理,然後寫到客戶端時,此時可能輸出流已經被相應到客戶端了。下圖是我們要實現的效果。
使用自己包裝好的repsonse,以達到sevlet直接向客戶端返回資料失效的效果。這樣我們就可以在過濾器中,對我們的請求資料和返回資料進行處理,使之完全在我們的控制範圍內。
原始碼
public class AESFilter implements Filter {
private final Logger LOG = LoggerFactory.getLogger(AESFilter.class);
/**
* aes 密匙
*/
@Value(“
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);
}
}
}