简体   繁体   中英

how to encrypt response data in filter

i am trying encrypt response data before it written into the HttpServletResponse, so i have implemented custom response wrapper and output streram and a filter classes,

Problem is i need to encrypt whole response data once, but there is no write(String content) method, but there are three methods available inside ServletOutputStream class which are write(int b) , write(byte[] b) and write(byte[] b, int off, int len) when i run the application only one method is called write(int b) .

So is there any workaround to get whole response data as string, where i can call encrypt(responseData) ?

my classes looks like:

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);
}

and

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];
        }
    }

}

and my custom output stream class looks like:

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();
    }
}

String str= new String( bufferedResponse .getCopy());

This will give you the string of the data in outputStream. I can see in your code you are writing bytes to out as well as copier. This copier can also be modified later.

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();

I have solved the problem by this way:

  1. created a custom ByteArrayOutputStream and PrintWriter instance in response wrapper class.
  2. modified getOutputStream() and getWriter() method to use custom instance created in step 1.
  3. finally, in filter after doFilter() statement, retrieved response data from custom writer and output stream. and written encrypted data to original response.

here is how response wrapper looks like:

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();
    }

}

and doFilter() looks like:

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();
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM