springboot项目拦截前端请求中的特殊字符串(解决方案)

 更新时间:2023年10月31日 15:15:05   作者:墨落成白123  
springboot项目中,需要对前端请求数据进行过滤,拦截特殊字符,本文通过实例代码给大家分享完美解决方案,感兴趣的朋友一起看看吧

项目场景:

springboot项目中,需要对前端请求数据进行过滤,拦截特殊字符。

问题描述

GET请求可以很方便的通过处理URL判断是否包含特殊字符,POST类型请求需要对form-data/json特殊处理,使用@RequestBody注解的controller获取不到数据

原因分析:

request中的getInputStream()方法和getReader()方法只能获取一次数据,通过@RequestBody注解再次获取getInputStream()拿到结果为空,此处通过重写getInputStream()方法和getReader()解决。贴出完整代码如下。

解决方案:

1、注册拦截器

package com.xxx;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
 * @author lsh
 * @version 1.0
 * @date 2022/4/1 16:54
 */
@Configuration
public class SpecialCharConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        if(registry!=null){
            registry.addInterceptor(new SpecialCharInterceptor()).addPathPatterns("/**");
        }
    }
}

2、注册过滤器

package com.xxx;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * @author lsh
 * @version 1.0
 * @date 2022/4/1 17:03
 */
@Component
@WebFilter(filterName="specialCharFilter",urlPatterns="/*")
public class SpecialCharFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest){
            requestWrapper = new SpecialCharHttpServletRequestWrapper((HttpServletRequest) request);
        }
        // 获取请求中的流,将取出来的字符串,再次转换成流,然后把它放入到新request对象中
        // 在chain.doFiler方法中传递新的request对象
        if(requestWrapper == null) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }
    @Override
    public void destroy() {
    }
}

3、自定义保存流数据

package com.xxx;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
 * 自定义保存流数据
 * @author lsh
 * @version 1.0
 * @date 2022/4/1 16:56
 */
public class SpecialCharHttpServletRequestWrapper extends HttpServletRequestWrapper {
    public final HttpServletRequest  request;
    private final String bodyStr;
    public SpecialCharHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.request = request;
        this.bodyStr = getBodyString();
    }
    /**
     * 获取请求Body
     * @return
     */
    public String getBodyString() {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = cloneInputStream(request.getInputStream());
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
    /**
     * 复制输入流
     * @param inputStream 输入流
     * @return
     */
    public InputStream cloneInputStream(ServletInputStream inputStream) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        try {
            while ((len = inputStream.read(buffer)) > -1) {
                byteArrayOutputStream.write(buffer, 0, len);
            }
            byteArrayOutputStream.flush();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        return byteArrayInputStream;
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(bodyStr.getBytes(Charset.forName("UTF-8")));
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bais.read();
            }
            @Override
            public void setReadListener(ReadListener listener) {
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public boolean isFinished() {
                return false;
            }
        };
    }
}

4、特殊字符拦截类(application/json的数据格式只能为json和json数组,根据业务场景自行调整)

package com.xxx;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 拦截请求中包含的特殊字符
 * @author lsh
 * @version 1.0
 * @date 2022/4/1 16:27
 */
public class UrlFilter {
    /**
     * 特殊字符正则表达式
     */
    private final static String REG_EX = "[`~!@#$%^*()+|{}\\[\\].<>/?!()【】‘;:”“'。,、\\\\]";
    /**
     * 判断url中是否含有特殊字符
     * @param urls 前端请求链接
     * @return 是否包含特殊字符
     */
    public static boolean checkSpecials(String urls) {
        try {
            if (StringUtils.isNotEmpty(urls)) {
                // url参数转义
                urls = URLDecoder.decode(urls, "utf-8");
                if (Pattern.compile(REG_EX).matcher(urls).find()) {
                    return true;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 判断formData值对象中是否包含特殊字符
     * @param map formData值对象
     * @return 是否包含特殊字符
     */
    public static boolean checkSpecials(Map<String,String[]> map){
        if(!map.isEmpty()){
            for(String[] paraArray : map.values()){
                for(String paraStr : paraArray){
                    if(Pattern.compile(REG_EX).matcher(paraStr).find()){
                        return true;
                    }
                }
            }
        }
        return false;
    }
    /**
     * 判断前端传过来的json和json数组中是否含有特殊字符
     * @param request 前端请求(包含json数据)
     * @return 是否包含特殊字符
     */
    public static boolean checkSpecials(HttpServletRequest request) {
        try {
            SpecialCharHttpServletRequestWrapper wrapper = new SpecialCharHttpServletRequestWrapper(request);
            InputStream is = wrapper.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            if (sb.length() > 0) {
                //判断json是否包含list数组,包含则先遍历数组再遍历对象值
                if (sb.toString().contains("[")){
                    List<Object> objectList = JSONObject.parseObject(sb.toString(), new TypeReference<List<Object>>() {});
                    for(Object objTemp:objectList){
                        Map<String, Object> map = JSONObject.parseObject(JSONObject.parseObject(objTemp.toString()).toJSONString(), new TypeReference<Map<String, Object>>() {});
                        for (Object object : map.values()) {
                            if (object != null) {
                                Matcher m = Pattern.compile(REG_EX).matcher(object.toString());
                                if (m.find()) {
                                    return true;
                                }
                            }
                        }
                    }
                }else{
                    Map<String, Object> map = JSONObject.parseObject(JSONObject.parseObject(sb.toString()).toJSONString(), new TypeReference<Map<String, Object>>() {});
                    for (Object object : map.values()) {
                        if (object != null) {
                            Matcher m = Pattern.compile(REG_EX).matcher(object.toString());
                            if (m.find()) {
                                return true;
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}

5、实现拦截器

package com.xxx;
import org.springframework.lang.Nullable;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 特殊字符过滤
 * @author lsh
 * @version 1.0
 * @date 2022/4/1 16:25
 */
public class SpecialCharInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        if("GET".equals(httpServletRequest.getMethod())){
            if(UrlFilter.checkSpecials(httpServletRequest.getQueryString())){
                throw new Exception("url中包含特殊字符");
            }
        }else{
            String contentType = httpServletRequest.getContentType();
            //处理form-data请求类型数据值
            if (contentType != null && contentType.contains("multipart/form-data")) {
                MultipartResolver resolver = new CommonsMultipartResolver(httpServletRequest.getSession().getServletContext());
                MultipartHttpServletRequest multipartRequest = resolver.resolveMultipart(httpServletRequest);
                if(UrlFilter.checkSpecials(multipartRequest.getParameterMap())){
                    throw new Exception("请求参数中包含特殊字符");
                }
            }
            else{
                if(UrlFilter.checkSpecials(httpServletRequest)){
                    throw new Exception("请求的数据中包含特殊字符 ");
                }
            }
        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}

到此这篇关于springboot项目拦截前端请求中的特殊字符串的文章就介绍到这了,更多相关springboot拦截特殊字符串内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Data JPA分页复合查询原理解析

    Spring Data JPA分页复合查询原理解析

    这篇文章主要介绍了Spring Data JPA分页复合查询原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • 如何从eureka获取服务的ip和端口号进行Http的调用

    如何从eureka获取服务的ip和端口号进行Http的调用

    这篇文章主要介绍了如何从eureka获取服务的ip和端口号进行Http的调用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 一文教你利用Stream API批量Mock数据的方法

    一文教你利用Stream API批量Mock数据的方法

    在日常开发的过程中我们经常会遇到需要mock一些数据的场景,比如说 mock 一些接口的返回或者说 mock 一些测试消息用于队列生产者发送消息。本文将教你如何通过 Stream API 批量 Mock 数据,需要的可以参考一下
    2022-09-09
  • 详解SpringBoot如何实现多环境配置

    详解SpringBoot如何实现多环境配置

    在实际的软件开发过程中,一个应用程序通常会有多个环境,pring Boot 提供了一个非常灵活和强大的方式来管理这些环境配置,下面就跟随小编一起学习一下吧
    2023-07-07
  • java微信公众号开发案例

    java微信公众号开发案例

    这篇文章主要为大家详细介绍了java微信公众号开发案例,如何接入公众号,订阅号怎么样接收消息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • java统计汉字字数的方法示例

    java统计汉字字数的方法示例

    这篇文章主要介绍了java统计汉字字数的方法,结合实例形式分析了java正则判定、字符串遍历及统计相关操作技巧,需要的朋友可以参考下
    2017-05-05
  • java 查找list中重复数据实例详解

    java 查找list中重复数据实例详解

    这篇文章主要介绍了java 查找list中重复数据实例详解的相关资料,需要的朋友可以参考下
    2017-01-01
  • java实现通过绑定邮箱找回密码功能

    java实现通过绑定邮箱找回密码功能

    这篇文章主要为大家详细介绍了java实现通过绑定邮箱找回密码功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • SpringCloud Config连接git与数据库流程分析讲解

    SpringCloud Config连接git与数据库流程分析讲解

    springcloud config是一个解决分布式系统的配置管理方案。它包含了 client和server两个部分,server端提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client端通过接口获取数据、并依据此数据初始化自己的应用
    2022-12-12
  • Reactor定制一个生产的WebClient实现示例

    Reactor定制一个生产的WebClient实现示例

    这篇文章主要为大家介绍了Reactor定制一个生产的WebClient实现示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08

最新评论