温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

spring boot如何实现在request里解密参数返回

发布时间:2021-09-15 10:43:29 来源:亿速云 阅读:156 作者:小新 栏目:开发技术

这篇文章将为大家详细讲解有关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,则直接通行             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);     } }

思路都在代码中备注了,就是在过滤器中,一层层解析,比如token等,然后再分别解析两种请求的参数,放入params里,其中用到的两个工具类如下

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 "参数" + key + "必填";     } }

RequestBodyUtil

import java.io.IOException; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; /**  * 解析Body数据  */ 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;     } }

最后

注册过滤器我就不说了,SpringBoot注册过滤器方式很多,看如何在控制器中接收参数

@PostMapping("/test")     public Result test(@RequestParam String params){         System.out.println("解密后的参数:" + params);         return ResponseMsgUtil.success(params);     }

名字只要和过滤器中自定义的Map里的Key对应,就会被拿到参数

Spring boot配置Aop获取controller里的request中的参数及其返回值

示例:

当前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()

  • 返回的是完整的url,包括Http协议,端口号,servlet名字和映射路径,但它不包含请求参数。

2、request.getRequestURI()

  • 得到的是request URL的部分值,并且web容器没有decode过的

3、request.getContextPath()

  • 返回 the context of the request.

4、request.getServletPath()

  • 返回调用servlet的部分url.

5、request.getQueryString()

  • 返回url路径后面的查询字符串

首先在你的Maven的pom文件里加入aop的依赖

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

在spring boot里面一切配置都是很简单的,

下面为我所有被请求到的controller加上Aop的功能

看码吧:

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   //定义一个切面 @Configuration public class LogRecordAspect { private static final Logger logger = LoggerFactory.getLogger(UserInterceptor.class);     // 定义切点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("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, queryString);         // result的值就是被拦截方法的返回值         Object result = pjp.proceed();         Gson gson = new Gson();         logger.info("请求结束,controller的返回值是 " + gson.toJson(result));         return result;     } }

只要加上上面这个类,Aop就算配置好了,不信,去访问以下你的Controller试试。对比以前配置aop的方式(xml文件),现在的配置都到Java代码里来了,@Configuration这个Annotation就是JavaConfig的典型代表,Spring boot在启动时会会自动去加载这些配置,实现相应的配置功能。

关于“spring boot如何实现在request里解密参数返回”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI