spring boot Implementation Decryption Parameter Return in request
- 2021-11-13 07:48:26
- OfStack
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()
2.
request.getRequestURI()
3.
request.getContextPath()
4.
request.getServletPath()
5.
request.getQueryString()
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.