spring boot Implementation Decryption Parameter Return in request

  • 2021-11-13 07:48:26
  • OfStack

Directory spring boot in request Decryption Parameter Return Preface Code Block Last Spring boot Configuration Aop Obtain request Parameter and Return Value in controller First in your Maven pom File Add aop Dependency Below for all my requested controller Plus Aop Function

spring boot Decryption parameter returns in request

Preface

There is a business requirement, one request source web, one request source APP and web need to verify the signature, and the parameters of APP are encrypted, so there are two Controller. Except for decryption, the parameters are obtained in different ways, and other contents are modeled and modeled, which is unreasonable, so I decided to reconstruct.

Train of thought: Since only decryption is not 1, the parameters obtained are 1, that can write a filter, in which the parameters are decrypted, and then return

Spring Boot is not allowed to directly modify paramsMap parameters in HttpServletRequest at the time of request, but an HttpServletRequestWrapper class is provided, and it is OK to inherit this class and override two methods.

Code block

Rewrite HttpServletRequestWrapper


import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
public class ParameterRequest extends HttpServletRequestWrapper {
    private Map<String, String[]> params = new HashMap<>(16);
    public ParameterRequest(HttpServletRequest request) throws IOException {
        super(request);
        this.params.putAll(request.getParameterMap());
    }
    /**
     *  Heavy load 1 A construction method 
     *
     * @param request
     * @param extendParams
     */
    public ParameterRequest(HttpServletRequest request, Map<String, String[]> extendParams) throws IOException {
        this(request);
        addAllParameters(extendParams);
    }
    @Override
    public String getParameter(String name) {
        String[] values = params.get(name);
        if (values == null || values.length == 0) {
            return null;
        }
        return values[0];
    }
    @Override
    public String[] getParameterValues(String name) {
        return params.get(name);
    }
    public void addAllParameters(Map<String, String[]> otherParams) {
        for (Map.Entry<String, String[]> entry : otherParams.entrySet()) {
            addParameter(entry.getKey(), entry.getValue());
        }
    }
    public void addParameter(String name, Object value) {
        if (value != null) {
            if (value instanceof String[]) {
                params.put(name, (String[]) value);
            } else if (value instanceof String) {
                params.put(name, new String[]{(String) value});
            } else {
                params.put(name, new String[]{String.valueOf(value)});
            }
        }
    }
}

The idea is to rewrite a custom Map save parameter, put the required parameters after decryption, and then execute this new request in the filter

Filter


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class WebParamFilter implements Filter {
    private static final String OPTIONS = "OPTIONS";
    @Value("${jwt.info.urlPatterns}")
    private List<String> urlPatterns;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        log.info(" Start filter ===============");
        if (!isFilter(request)) {
            writerError(response, RetEnum.RET_TOKEN_ERROR);
            return;
        }
        //  Get the request type from the request header, 1 Yes WEB , 2 Yes APP
        String requestType = request.getHeader("requestType");
        if (StringUtils.isEmpty(requestType)) {
            writerError(response, RetEnum.RET_NOT_HEADER_ERROR);
            return;
        }
        Map<String, String[]> paramsMap = new HashMap<>();
        if ("1".equals(requestType)) {
        	//  Verify the signature, and return the signature error directly 
            if (!compareSign(request)) {
                writerError(response, " Signature error ", 500);
                return;
            }
            //  Will the requested parameters from the request And converts to JSON To put the custom Map Bring to controller in 
            paramsMap.put("params", new String[]{JSONUtil.getJSONParam(request).toJSONString()});
            ParameterRequest req = new ParameterRequest(request, paramsMap);
            filterChain.doFilter(req, response);
        } else if ("2".equals(requestType)) {
        	// APP The request method is special, so you should start from requestBody Read in JSON Encrypted data 
            String bodyStr = RequestBodyUtil.read(request.getReader());
            //  Then decrypt, get the real parameters and convert them into JSON To put the custom Map Bring to controller in 
            JSONObject jsonParam = getJsonParam(bodyStr);
            paramsMap.put("params", new String[]{jsonParam.toJSONString()});
            ParameterRequest req = new ParameterRequest(request, paramsMap);
            filterChain.doFilter(req, response);
        } else {
            writerError(response, " Invalid request source ", 500);
        }
    }
    @Override
    public void destroy() {
    }
    /**
     *  Screening 
     *
     * @param request
     * @return
     */
    private boolean isFilter(HttpServletRequest request) {
        if (OPTIONS.equals(request.getMethod())) {
            return true;
        }
        if (isInclude(request)) {
            // If it is excluded, URL Such as login, registration, verification code, etc. URL , then pass directly 
            log.info(" Direct through ");
            return true;
        }
        return tokenCheck(request);
    }
    /**
     *  Exclude those that do not need filtering URL
     *
     * @param request
     * @return
     */
    private boolean isInclude(HttpServletRequest request) {
        String url = request.getRequestURI().substring(request.getContextPath().length());
        log.info(" Request url:{}", url);
        for (String patternUrl : urlPatterns) {
            Pattern p = Pattern.compile(patternUrl);
            Matcher m = p.matcher(url);
            if (m.find()) {
                return true;
            }
        }
        return false;
    }
    /**
     *  Efficacy token Is it valid 
     *
     * @param request
     * @return
     */
    private boolean tokenCheck(HttpServletRequest request) {
        String authToken = request.getHeader("accessToken");
        log.info(" Token in request header token:{}", authToken);
        // ... Business code 
        return false;
    }
    /**
     *  Write out by mistake 
     *
     * @param response
     * @param retEnum
     * @throws IOException
     */
    private void writerError(HttpServletResponse response, String msg, int code) throws IOException {
        // Validation failed 
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        // Returns an error that fails validation 
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("code", code);
        resultMap.put("msg", msg);
        resultMap.put("data", null);
        response.getWriter().write(mapper.writeValueAsString(resultMap));
    }
    /**
     * web Valid signature 
     *
     * @param request
     * @return
     */
    public boolean compareSign(HttpServletRequest request) {
        JSONObject param = JSONUtil.getJSONParam(request);
        String sign = JSONUtil.getParamRequired(param, String.class, "sign");
       // ... Business code 
        return s.equals(sign);
    }
 	/**
     * APP Decryption parameter 
     *
     * @param json
     * @return
     */
    public JSONObject getJsonParam(String json) {
        JSONObject jsonParam = JSON.parseObject(json);
        String aos = jsonParam.getString("aos");
        String params = jsonParam.getString("params");
        String param = null;
        if (jsonParam != null && !StringUtils.isEmpty(aos) && !StringUtils.isEmpty(params)) {
            String key = RSA.rsaDecrypt(aos, " Custom private key ");
            if (StringUtils.isBlank(key)) {
                return null;
            }
            try {
                param = AES256.decrypt(params, key);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (StringUtils.isBlank(param)) {
                return null;
            }
        }
        if (StringUtils.isBlank(param)) {
            return null;
        }
        return JSONObject.parseObject(param);
    }
}

Ideas are in the code notes, is in the filter, 1 layer parsing, such as token, and then parsing the parameters of the two requests, put into params, which used two tool classes as follows

JSONUtil


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.MissingServletRequestParameterException;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
public class JSONUtil {
    public static JSONObject getJSONParam(HttpServletRequest request){
        Map<String, String[]> parameterMap = request.getParameterMap();
        JSONObject returnObject = new JSONObject();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String value = "";
            String[] values = entry.getValue();
            if (values != null){
                for (String s : values) {
                    value = s + ",";
                }
                value = value.substring(0, value.length() - 1);
            }
            returnObject.put(entry.getKey(), value);
        }
        return returnObject;
    }
    public static<T> T getParam(JSONObject param, Class<T> tClass, String key){
        if (param == null) {
            return null;
        }
        return param.getObject(key, tClass);
    }
    public static<T> T getParamRequired(JSONObject param, Class<T> tClass, String key){
        if (param == null) {
            throw new RuntimeException(getErrMsg(key));
        }
        T object = param.getObject(key, tClass);
        if (object == null){
            throw new RuntimeException(getErrMsg(key));
        }
        return object;
    }
    private static String getErrMsg(String key) {
        return " Parameter " + key + " Required ";
    }
}

RequestBodyUtil


import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
/**
 *  Analyse Body Data 
 */
public class RequestBodyUtil {
    private static final int BUFFER_SIZE = 1024 * 8;
    private RequestBodyUtil(){}
    public static String read(Reader reader) throws IOException {
        StringWriter writer = new StringWriter();
        try {
            write(reader, writer);
            return writer.getBuffer().toString();
        } finally {
            writer.close();
        }
    }
    public static long write(Reader reader, Writer writer) throws IOException {
        return write(reader, writer, BUFFER_SIZE);
    }
    public static long write(Reader reader, Writer writer, int bufferSize) throws IOException {
        int read;
        long total = 0;
        char[] buf = new char[BUFFER_SIZE];
        while ((read = reader.read(buf)) != -1) {
            writer.write(buf, 0, read);
            total += read;
        }
        return total;
    }
}

Finally

I will not say the registration filter, SpringBoot registration filter many ways, see how to receive parameters in the controller


    @PostMapping("/test")
    public Result test(@RequestParam String params){
        System.out.println(" Parameters after decryption: " + params);
        return ResponseMsgUtil.success(params);
    }

As long as the name corresponds to Key in the custom Map in the filter, it will be given parameters

Spring boot Configuration Aop Obtains the parameters in request in controller and their return values

Example:

Current url: http://localhost: 8080/CarsiLogCenter _ new/idpstat. jsp? action = idp. sptopn


request.getRequestURL() http://localhost:8080/CarsiLogCenter_new/idpstat.jsp
request.getRequestURI() /CarsiLogCenter_new/idpstat.jsp
request.getContextPath()/CarsiLogCenter_new
request.getServletPath() /idpstat.jsp
request.getQueryString() action=idp.sptopn

    public static String getLastAccessUrl(HttpServletRequest request) {
        StringBuffer requestURL = request.getRequestURI();
        String queryString = request.getQueryString();
        if (queryString == null) {
            return requestURL.toString();
        }
        return requestURL + "?" + queryString;
    }

1. request.getRequestURL()

The complete url is returned, including the Http protocol, port number, servlet name, and mapping path, but it does not contain the request parameters.

2. request.getRequestURI()

What is obtained is the partial value of request URL, and the web container does not have decode

3. request.getContextPath()

Returns the context of the request.

4. request.getServletPath()

Returns the part of url that calls servlet.

5. request.getQueryString()

Returns the query string after the url path

First add aop dependencies to your Maven pom file


  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
  </dependency>

In spring boot, 1-cut configuration is very simple.

The following is the function of controller plus Aop for all my requests

Look at the code:


import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;;
@Aspect   // Definition 1 Three sections 
@Configuration
public class LogRecordAspect {
private static final Logger logger = LoggerFactory.getLogger(UserInterceptor.class);
    //  Define tangent point Pointcut
    @Pointcut("execution(* com.jiaobuchong.web.*Controller.*(..))")
    public void excudeService() {
    }
    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        String url = request.getRequestURL().toString();
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String queryString = request.getQueryString();
        logger.info(" Request start ,  Parameters , url: {}, method: {}, uri: {}, params: {}", url, method, uri, queryString);
        // result Is the return value of the intercepted method 
        Object result = pjp.proceed();
        Gson gson = new Gson();
        logger.info(" End of request, controller The return value of is  " + gson.toJson(result));
        return result;
    }
}

As long as you add the above class, Aop is configured. If you don't believe it, try visiting your Controller below. Compared with the previous way of configuring aop (xml file), the current configuration comes to Java code. @ Configuration, an Annotation, is a typical representative of JavaConfig, and Spring boot will automatically load these configurations when starting up to realize corresponding configuration functions.


Related articles: