java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > springboot拦截特殊字符串

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

作者:墨落成白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拦截特殊字符串内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文