2014-11-25 58 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