spring boot在request里解密参数返回
前言
有个业务需求,一个请求来源web,一个请求来源APP,web需求验证签名,APP的参数是经过加密,所以出现了两个Controller,除了解密获取参数方式不一样,其他内容一模一样,这样不太合理,所以我决定重构。
思路:既然只是解密不一样,获取到的参数是一样的,那可以写一个过滤器,在里面就把参数解密好,然后返回
Spring Boot在请求的时候是不允许直接修改HttpServletRequest里的paramsMap参数的,但是提供了一个HttpServletRequestWrapper类,继承这个类重写两个方法就可以了。
代码块
重写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()); } /** * 重载一个构造方法 * * @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)}); } } } }
思路是重写自定义一个Map存入参数,将解密后需要的参数放入,然后在过滤器中执行这个新的request
过滤器
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("开始过滤器==============="); if (!isFilter(request)) { writerError(response, RetEnum.RET_TOKEN_ERROR); return; } // 从请求头从获取请求类型,1是WEB,2是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)) { // 验证签名,签名错误直接返回 if (!compareSign(request)) { writerError(response, "签名错误", 500); return; } // 将请求的参数从request中取出,转换成JSON,放入自定义的Map中带给控制器 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请求方式比较特殊,所以要从requestBody里读出JSON加密数据 String bodyStr = RequestBodyUtil.read(request.getReader()); // 然后再解密,拿到真正的参数转换成JSON,放入自定义的Map中带给控制器 JSONObject jsonParam = getJsonParam(bodyStr); paramsMap.put("params", new String[]{jsonParam.toJSONString()}); ParameterRequest req = new ParameterRequest(request, paramsMap); filterChain.doFilter(req, response); } else { writerError(response, "无效的请求来源", 500); } } @Override public void destroy() { } /** * 筛选 * * @param request * @return */ private boolean isFilter(HttpServletRequest request) { if (OPTIONS.equals(request.getMethod())) { return true; } if (isInclude(request)) { //如果是属于排除的URL,比如登录,注册,验证码等URL,则直接通行 <strong>本文来源gaodai#ma#com搞@代~码^网+</strong> log.info("直接通过"); return true; } return tokenCheck(request); } /** * 排除不需要过滤的URL * * @param request * @return */ private boolean isInclude(HttpServletRequest request) { String url = request.getRequestURI().substring(request.getContextPath().length()); log.info("请求url:{}", url); for (String patternUrl : urlPatterns) { Pattern p = Pattern.compile(patternUrl); Matcher m = p.matcher(url); if (m.find()) { return true; } } return false; } /** * 效验token是否有效 * * @param request * @return */ private boolean tokenCheck(HttpServletRequest request) { String authToken = request.getHeader("accessToken"); log.info("请求头中令牌token:{}", authToken); // ...业务代码 return false; } /** * 错误写出 * * @param response * @param retEnum * @throws IOException */ private void writerError(HttpServletResponse response, String msg, int code) throws IOException { //验证不通过 response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); //将验证不通过的错误返回 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效验签名 * * @param request * @return */ public boolean compareSign(HttpServletRequest request) { JSONObject param = JSONUtil.getJSONParam(request); String sign = JSONUtil.getParamRequired(param, String.class, "sign"); // ...业务代码 return s.equals(sign); } /** * APP解密参数 * * @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, "自定义的私钥"); 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); } }