简体   繁体   中英

replace/prepare raw POST data before using HttpServletRequest in Spring MVC

I have api-based client-server application, php+yii as backend. My goal is to make port of backend part from php to java (compatible with old queries from client).

I chose Spring MVC framework, but got stuck on problem with decrypting raw post data. The issue is that old client uses custom encryption algorithm, so HttpServletRequest.getParameterMap() doesn't return valid map.

So, my question is: In this situation, what is the best solution for replacing/preparing raw post data (decrypting) before using request.getParameterMap() method for pure business logic?

Controller code is something like this:

@RestController
@RequestMapping(value = "/", method = RequestMethod.POST)
public class ApiController {

    @RequestMapping
    @ResponseBody
    public String process(HttpServletRequest request) {
        ApiQueryResponse queryResponse = new ApiQueryResponse();

        try {
            // request = APIEncryptor.decrypt(request);         // 1
            // now working with request.getParameterMap()       // 2
            // ...
            queryResponse.setText(APIEncryptor.crypt(...))
        } catch (Exception e) {
            queryResponse.setError(e.getMessage());
        }

        return queryResponse.asText();
    }

    ...

}

APIEncryptor code is something like this:

public class ApiEncryptor {
    public static ApiQueryData encrypt(Java Object) {
        // custom encryption algorithm...
        return Raw data string;
    }

    // input post data: 103klg20fsl2g2fsldkfj20f9isjf
    // output post data: a=1&b=2&c=3&d=some_text

    public static ApiQueryData decrypt(Raw post data...) {
        // decrypt algorithm...
        return request; // HttpServletRequest object with valid post data
        // after this action, .getParameter() will produce valid data
    }
}

note: I know what method such as request.getInputStream() exists, but I don't need it right now. I need to know is there any way to just prepare post data before using HttpServletRequest parameter getters? OR (anyway) I need to get post data from request once and do what I want (by getReader(), for example)?

The best way to handle your decryption logic is inside a http filter (uses spring MVC) as below. This filter decrypts the requests immediately after receiving the request to server and before reaching the controller method.

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.filter.OncePerRequestFilter;

public class DecryptionFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        request = ApiEncryptor.decrypt(request);

        filterChain.doFilter(request, response);
    }

}

HttpServletRequest Decrypt before controller in Filter with Spring Boot and java 8

public class RequestWrapper extends HttpServletRequestWrapper {

private final String body;

public RequestWrapper(HttpServletRequest request) throws Exception {
    super(request);

    StringBuilder stringBuilder = new StringBuilder();
    BufferedReader bufferedReader = null;
    try {
        InputStream inputStream = request.getInputStream();
        if (inputStream != null) {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            char[] charBuffer = new char[128];
            int bytesRead = -1;
            while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                stringBuilder.append(charBuffer, 0, bytesRead);
            }
        } else {
            stringBuilder.append("");
        }
    } catch (IOException ex) {
        throw ex;
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException ex) {
                throw ex;
            }
        }
    }
    String encryptData = stringBuilder.toString();
    String deCryptData = null;
    if (encryptData != null && !encryptData.isEmpty()) {
        deCryptData = MD5Utils.decrypt(encryptData);
        if (deCryptData == null) {
            //logger.error("Exception occured inside MD5Utils.decrypt(encryptData) - Request Body not valid : ");
        }
    }
    body = deCryptData;
}

@Override
public ServletInputStream getInputStream() throws IOException {
    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
    ServletInputStream servletInputStream = new ServletInputStream() {
        public int read() throws IOException {
            return byteArrayInputStream.read();
        }

        @Override
        public boolean isFinished() {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean isReady() {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void setReadListener(ReadListener listener) {
            // TODO Auto-generated method stub

        }
    };
    return servletInputStream;
}

@Override
public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(this.getInputStream()));
}

public String getBody() {
    return this.body;
}

}

Filter class

public class MyFilter implements Filter {
  @Override
  public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

    /* wrap the request in order to read the inputstream multiple times */
    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    request = new RequestWrapper(httpServletRequest);  

    chain.doFilter(request, response);
  }
}

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