2014-11-25 59 views
2

我試圖加密的響應數據之前寫入HttpServletResponse的,所以我已經實現自定義的響應包裝和輸出streram和過濾器類,如何在過濾器加密響應數據

問題是我需要加密整個響應數據一次,但沒有write(String content)方法,但有三種方法可用在ServletOutputStream類中,分別是write(int b),write(byte[] b)write(byte[] b, int off, int len)當我運行應用程序時,只有一種方法叫做write(int b)

那麼是否有任何解決方法來獲取整個響應數據作爲字符串,在那裏我可以調用encrypt(responseData)?

我的課是這樣的:

public void doFilter(ServletRequest request, ServletResponse response, 
      FilterChain chain) throws IOException, ServletException { 

     HttpServletRequest httpServletRequest = (HttpServletRequest)request; 
     HttpServletResponse httpServletResponse = (HttpServletResponse)response; 
     BufferedRequestWrapper bufferedReqest = new BufferedRequestWrapper(httpServletRequest); 
     BufferedServletResponseWrapper bufferedResponse = new BufferedServletResponseWrapper(httpServletResponse); 

     // pass the wrappers on to the next entry 
     chain.doFilter(bufferedReqest, bufferedResponse); 
} 

public class BufferedServletResponseWrapper extends HttpServletResponseWrapper { 

    private final Logger LOG = LoggerFactory.getLogger(getClass()); 

    private ServletOutputStream outputStream; 
    private PrintWriter writer; 
    private MyServletOutputStream copier; 

    public BufferedServletResponseWrapper(HttpServletResponse response) throws IOException {   
     super(response); 
    } 

    @Override 
    public ServletOutputStream getOutputStream() throws IOException { 
     LOG.info("getOutputStream"); 
     if (writer != null) { 
      throw new IllegalStateException("getWriter() has already been called on this response."); 
     } 

     if (outputStream == null) { 
      outputStream = getResponse().getOutputStream(); 
      copier = new MyServletOutputStream(outputStream); 
     } 

     return copier; 
    } 

    @Override 
    public PrintWriter getWriter() throws IOException { 
     LOG.info("getWriter"); 
     if (outputStream != null) { 
      throw new IllegalStateException("getOutputStream() has already been called on this response."); 
     } 

     if (writer == null) { 
      copier = new MyServletOutputStream(getResponse().getOutputStream()); 
      writer = new PrintWriter(new OutputStreamWriter(copier, getResponse().getCharacterEncoding()), true); 
     } 

     return writer; 
    } 

    @Override 
    public void flushBuffer() throws IOException { 
     if (writer != null) { 
      writer.flush(); 
     } else if (outputStream != null) { 
      copier.flush(); 
     } 
    } 

    public byte[] getCopy() { 
     if (copier != null) { 
      return copier.getCopy(); 
     } else { 
      return new byte[0]; 
     } 
    } 

} 

和我的自定義輸出流類的樣子:

public class MyServletOutputStream extends ServletOutputStream{ 

    private final Logger LOG = LoggerFactory.getLogger(getClass()); 

    private OutputStream outputStream; 
    private ByteArrayOutputStream copy; 

    public MyServletOutputStream(OutputStream outputStream) { 
     this.outputStream = outputStream; 
     this.copy = new ByteArrayOutputStream(1024); 
    } 

    @Override 
    public void write(int b) throws IOException { 
     LOG.info("write int"); 

     outputStream.write(b); 
     copy.write(b); 
    } 

    @Override 
    public void write(byte[] b) throws IOException { 
     LOG.info("write byte[]"); 

     outputStream.write(b); 
     copy.write(b); 
    } 

    public byte[] getCopy() { 
     return copy.toByteArray(); 
    } 
} 
+0

你可以把每個字節在它自己的成['密碼#更新(字節[1])'](https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html#update%28byte []%29),然後得到最終結果。或者通過一些密碼流 – zapl 2014-11-25 10:50:17

+1

想知道這裏的'CipherOutputStream'會有幫助嗎? https://docs.oracle.com/javase/7/docs/api/javax/crypto/CipherOutputStream.html – Qwerky 2014-11-25 10:51:15

+0

@Qwerky感謝您的快速回復,任何實例如何使用它。 – Rembo 2014-11-25 14:32:21

回答

1

我已經通過這種方式解決了這個問題:

  1. 創建響應包裝類的自定義ByteArrayOutputStream和PrintWriter的實例。
  2. 修改getOutputStream()和getWriter()方法以使用在步驟1中創建的自定義實例。
  3. 最後,在過濾器執行doFilter()語句後,從自定義寫入器和輸出流中檢索響應數據。並將加密數據寫入原始響應。

這裏是響應包裝的樣子:

public class BufferedServletResponseWrapper extends HttpServletResponseWrapper { 

     private final Logger LOG = LoggerFactory.getLogger(getClass()); 

    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
    private PrintWriter writer = new PrintWriter(outputStream); 

    public BufferedServletResponseWrapper(HttpServletResponse response) 
      throws IOException { 
     super(response); 
    } 

    @Override 
    public ServletOutputStream getOutputStream() throws IOException { 
     LOG.info("getOutputStream"); 

     return new ServletOutputStream() { 
      @Override 
      public void write(int b) throws IOException { 
       LOG.info("write int"); 

       outputStream.write(b); 
      } 

      @Override 
      public void write(byte[] b) throws IOException { 
       LOG.info("write byte[]"); 

       outputStream.write(b); 
      } 
     }; 
    } 

    @Override 
    public PrintWriter getWriter() throws IOException { 
     LOG.info("getWriter"); 
     return writer; 
    } 

    @Override 
    public void flushBuffer() throws IOException { 
     if (writer != null) { 
      writer.flush(); 
     } else if (outputStream != null) { 
      outputStream.flush(); 
     } 
    } 

    public String getResponseData() { 
     return outputStream.toString(); 
    } 

} 

和的doFilter()看起來像:

public void doFilter(ServletRequest request, ServletResponse response, 
      FilterChain chain) throws IOException, ServletException { 

     HttpServletRequest httpServletRequest = (HttpServletRequest) request; 
     HttpServletResponse httpServletResponse = (HttpServletResponse) response; 
     BufferedServletResponseWrapper bufferedResponse = new BufferedServletResponseWrapper(
       httpServletResponse); 

     // pass the wrappers on to the next entry 
     chain.doFilter(httpServletRequest, bufferedResponse); 

     String responseData = bufferedResponse.getResponseData(); 
     String encryptedResponseData = encrypt(responseData); 
     OutputStream outputStream = httpServletResponse.getOutputStream(); 
     outputStream.write(encryptedResponseData.getBytes()); 
     outputStream.flush(); 
     outputStream.close(); 
    } 
2

字符串str =新的String(bufferedResponse .getCopy( ));

這會給你outputStream中的數據字符串。我可以在你的代碼中看到你正在寫字節以及複印機。這臺複印機也可以稍後修改。

String encStr=Encrypt(str); // your encryption logic. 

ServletOutputStream out= response.getOutputStream(); 

out.write(encStr.getByte()); //adding your encrypted data to response 
out.flush(); 
out.close(); 
+0

感謝您的回答。但您必須傳遞自定義輸出流和作者而不是原始輸出流。 – Rembo 2014-11-29 04:02:56

+0

我懷疑你的doFilter中的outputStream將包含響應數據以及在最後附加的編碼數據,即使你正在使用自定義outputStreams。我覺得你需要一個假冒作家來過來。如果錯了,請糾正我。 – Abs 2014-11-29 07:44:24