zoukankan      html  css  js  c++  java
  • AOP日志组件 多次获取post参数

    AOP日志组件 多次获取post参数

    • 需求:新增接口日志组件。通过拦截器对接口URL进行拦截处理,然后将接口post请求的参数与结果,写入日志表。
    • 问题:POST方法的参数是存储在request.getInputStream中,只能读一次,不能多次读取。从中读取post请求参数,只能读取一次。在filter中获取之后,controller无法获取post请求参数。
    • 解决办法:继承HttpServletRequest,先获取到请求参数,再加参数重新set到inputStream。

    1.拦截器记录日志

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest httpRequest = (HttpServletRequest)request;
            String requestPath  = httpRequest.getServletPath().split("\?")[0];
    
            if(request  == null){
                chain.doFilter(request, response);
                return ;
            }
             for (String noFilter : NO_FILETER_LIST) {
                 if(requestPath.toLowerCase().contains(noFilter)){
                     chain.doFilter(request, response);
                     return ;
                 }
             }
    
             Pattern pattern = Pattern.compile(".*[api|interface].*");
             Matcher matcher = pattern.matcher(requestPath);
             if(matcher.matches()){
                 LoggerManager loggerManager = SpringLoadListener.getBean("loggerManager",LoggerManager.class);
                 //扩展request,防止字符注入等
                 XssSqlHttpServletRequestWrapper xssRequest = new XssSqlHttpServletRequestWrapper((HttpServletRequest)request);
                 ResponseWrapper wrapResponse = new ResponseWrapper((HttpServletResponse)response);
                 //继续请求处理类
                 chain.doFilter(xssRequest, wrapResponse);
                 //获取URL的参数 get请求
                 Map<Object, Object> urlParam = xssRequest.getParameterMap();
                 //获取post参数
                 String param = xssRequest.getRequestParams();
                 JSONObject jObject = JSONObject.fromObject(urlParam);
                 jObject.put("postParam", param.toString());
                 String params = jObject.toString();
                 //获取接口处理类返回结果
                 byte[] data = wrapResponse.getResponseData();
                  String result = new String(data,"UTF-8");
                  //保存日志
                  loggerManager.operateInterfaceLogger("", params, requestPath, result);
                  ServletOutputStream out = response.getOutputStream();
                  out.write(data);
                  out.flush();
             }else{
                 chain.doFilter(request, response);
             }
    
        }

    2.处理request请求,先获取inputStream,将请求参数复制给其他方法,同时再将获取的inputStream赋值回request中。

    public class XssSqlHttpServletRequestWrapper extends HttpServletRequestWrapper
     {
             HttpServletRequest orgRequest = null;
             private byte[] bytes;
             private WrappedServletInputStream  wrappedServletInputStream;
    
       public XssSqlHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
               super(request);
               this.orgRequest = request;
               //读取输入流的请求参数,保存到bytes中
               bytes = IOUtils.toByteArray(request.getInputStream());
               ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
               this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream);
    
               //把post参数重新写入请求流
               reWriteInputStream();
       }
    
       /**
        * 把参数重新写进请求里
        */
        public void reWriteInputStream() {
           wrappedServletInputStream.setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0]));
       }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
            return wrappedServletInputStream;
        }
    
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(wrappedServletInputStream));
        }
    
        /**
         * 获取post参数
         */
        public String getRequestParams() throws IOException {
            return new String(bytes, this.getCharacterEncoding());
        }
    
       //清洗参数,防止xss注入
       public String[] getParameterValues(String parameter)
       {
               String[] values = super.getParameterValues(parameter);
               if (values == null) {
                 return null;
         }
               int count = values.length;
               String[] encodedValues = new String[count];
               for (int i = 0; i < count; i++) {
                 encodedValues[i] = xssEncode(values[i]);
         }
               return encodedValues;
       }
    
    
       public String getParameter(String name)
       {
               String value = super.getParameter(xssEncode(name));
               if (value != null) {
                 value = xssEncode(value);
         }
               return value;
       }
    
       public String getHeader(String name)
       {
               String value = super.getHeader(xssEncode(name));
               if (value != null) {
                 value = xssEncode(value);
         }
               return value;
       }
    
    
       private static String xssEncode(String s)
       {
               return StringUtil.xssEncode(s);
       }
    
    
    
    
    
       public HttpServletRequest getOrgRequest()
       {
               return this.orgRequest;
       }
    
    
       public static HttpServletRequest getOrgRequest(HttpServletRequest req)
       {
               if ((req instanceof XssSqlHttpServletRequestWrapper)) {
                 return ((XssSqlHttpServletRequestWrapper)req).getOrgRequest();
         }
    
             return req;
       }
    
    
       private class WrappedServletInputStream extends ServletInputStream {
           public void setStream(InputStream stream) {
               this.stream = stream;
           }
           private InputStream stream;
           public WrappedServletInputStream(InputStream stream) {
               this.stream = stream;
           }
           public int read() throws IOException {
               return stream.read();
           }
    
           public boolean isFinished() {
               return true;
           }
    
           public boolean isReady() {
               return true;
           }
    
           public void setReadListener(ReadListener readListener) {
    
           }
       }
    
     }

    3.Manager保存日志记录。对LoggerAnnotation自定义注解,实现AOP日志保存。

    @LoggerAnnotation(type="INTERFACE", name="#name", params="#params", desc="#pageLink")
    public String operateInterfaceLogger(String name, String params, String pageLink, String result)
    {
        return result;
    
    }
    
    
     @Component
     @Aspect
     @Async
     public class LoggerOperationAop
     {
       private static final Logger logger = LoggerFactory.getLogger(LoggerOperationAop.class);
       @Autowired
       private LoggerManager loggerManager;
       @Autowired
       private UserManager userManager;
       @Autowired
       private JdbcTemplateImpl jdbcTemplate;
    
       public LoggerOperationAop() {}
    
       @Pointcut("@annotation(LoggerAnnotation)")
       private void serviceAspect(LoggerAnnotation LoggerAnnotation) {}
    
       @Around("serviceAspect(LoggerAnnotation)")
       public Object process(ProceedingJoinPoint point, LoggerAnnotation LoggerAnnotation)
         throws Throwable
       {
         String targetName = point.getTarget().getClass().getName();
         String methodName = point.getSignature().getName();
         Object[] arguments = point.getArgs();
    
         String operationType = LoggerAnnotation.type();
         String message = LoggerAnnotation.desc();
         String params = LoggerAnnotation.params();
         String name = LoggerAnnotation.name();
         String id = LoggerAnnotation.id();
         String[] paramNames = ReflectParamNames.getNames(targetName, methodName);
         if ((StringUtil.isNotBlank(name)) && (name.startsWith("#"))) {
           String value = SpelParser.getKey(name, "", paramNames, arguments);
           if (StringUtil.isNotBlank(value)) {
             targetName = value;
           }
         }
         String methodParams = "";
         if ((StringUtil.isNotBlank(params)) && (params.startsWith("#"))) {
           methodParams = SpelParser.getKey(params, "", paramNames, arguments);
         }
         if ((StringUtil.isNotBlank(message)) && (message.startsWith("#"))) {
           String value = SpelParser.getKey(message, "", paramNames, arguments);
           if (StringUtil.isNotBlank(value)) {
             message = value;
           }
         }
    
         String userId = null;
         String userName = "游客";
         try {
             Subject currentSubject = SecurityUtils.getSubject();
             if (currentSubject != null) {
               Object tmpObj = currentSubject.getSession().getAttribute("authorizeUser");
               if ((tmpObj != null) && ("INTERFACE".equals(operationType))) {
                 userName = StringUtil.parseAny2String(tmpObj);
               } else if (currentSubject.getPrincipal() != null) {
                 ShiroDbRealm.ShiroUser shiroUser = (ShiroDbRealm.ShiroUser)currentSubject.getPrincipal();
                 userId = shiroUser.getUserId();
                 userName = shiroUser.getLoginName();
               }
             }
           } catch (Exception e) {
             logger.info("不支持shiro技术框架");
             logger.error("异常信息:{}", e.getMessage());
           }
    
         Object target = point.proceed();
         try
         {
           String extName = DateUtil.getYearMonth(new Date());
           String sql = " INSERT INTO T_E4S_DB_LOG_MESSAGE_" + extName + 
             " (USER_ID,USER_NAME,CLASS_NAME,METHOD_NAME,METHOD_PARAMS,LOG_DATE,LOG_MESSAGE,OPERATION_TYPE,REMARK) " + 
             " VALUES(?,?,?,?,?,?,?,?,?) ";
           Object[] object = { userId, userName, targetName, methodName, methodParams, 
             new Date(), message, operationType, target };
           this.jdbcTemplate.beginTranstaion();
           this.jdbcTemplate.update(sql, object);
           this.jdbcTemplate.commit();
         }
         catch (Exception ex) {
           logger.error("==异常通知异常==");
           logger.error("异常信息:{}", ex.getMessage());
           this.jdbcTemplate.rollback();
         }
    
         return target;
       }
     }
    

    LoggerFilter里一个实现了XssSqlHttpServletRequestWrapper类,其构造器自动读取了servletRequest里的输入流,并把数据保存了下来,最后又把数据重新写入servletRequest里,在filter中可以读取post请求参数,cotroller也可以再次从request里读取到post请求参数。

  • 相关阅读:
    shell log
    Python:列出列表中所有元素的组合可能
    scrapy 停止爬虫
    shell split log by data
    mitmproxy 配置
    插件reres的使用,替换网站的js文件
    解决小米Note adb调试无法发现设备
    md5 计算文件一致性
    【Frida Hook 学习记录】Frida Hook Android 常用方法
    监控神器普罗米修斯Prometheus安装配置
  • 原文地址:https://www.cnblogs.com/lanxuan826/p/9873694.html
Copyright © 2011-2022 走看看