springboot項(xiàng)目攔截前端請(qǐng)求中的特殊字符串(解決方案)
項(xiàng)目場景:
springboot項(xiàng)目中,需要對(duì)前端請(qǐng)求數(shù)據(jù)進(jìn)行過濾,攔截特殊字符。
問題描述
GET請(qǐng)求可以很方便的通過處理URL判斷是否包含特殊字符,POST類型請(qǐng)求需要對(duì)form-data/json特殊處理,使用@RequestBody注解的controller獲取不到數(shù)據(jù)
原因分析:
request中的getInputStream()方法和getReader()方法只能獲取一次數(shù)據(jù),通過@RequestBody注解再次獲取getInputStream()拿到結(jié)果為空,此處通過重寫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);
}
// 獲取請(qǐng)求中的流,將取出來的字符串,再次轉(zhuǎn)換成流,然后把它放入到新request對(duì)象中
// 在chain.doFiler方法中傳遞新的request對(duì)象
if(requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
}
}3、自定義保存流數(shù)據(jù)
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;
/**
* 自定義保存流數(shù)據(jù)
* @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();
}
/**
* 獲取請(qǐng)求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();
}
/**
* 復(fù)制輸入流
* @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的數(shù)據(jù)格式只能為json和json數(shù)組,根據(jù)業(yè)務(wù)場景自行調(diào)整)
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;
/**
* 攔截請(qǐng)求中包含的特殊字符
* @author lsh
* @version 1.0
* @date 2022/4/1 16:27
*/
public class UrlFilter {
/**
* 特殊字符正則表達(dá)式
*/
private final static String REG_EX = "[`~!@#$%^*()+|{}\\[\\].<>/??。ǎ尽俊?;:”“'。,、\\\\]";
/**
* 判斷url中是否含有特殊字符
* @param urls 前端請(qǐng)求鏈接
* @return 是否包含特殊字符
*/
public static boolean checkSpecials(String urls) {
try {
if (StringUtils.isNotEmpty(urls)) {
// url參數(shù)轉(zhuǎn)義
urls = URLDecoder.decode(urls, "utf-8");
if (Pattern.compile(REG_EX).matcher(urls).find()) {
return true;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return false;
}
/**
* 判斷formData值對(duì)象中是否包含特殊字符
* @param map formData值對(duì)象
* @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數(shù)組中是否含有特殊字符
* @param request 前端請(qǐng)求(包含json數(shù)據(jù))
* @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數(shù)組,包含則先遍歷數(shù)組再遍歷對(duì)象值
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、實(shí)現(xiàn)攔截器
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請(qǐng)求類型數(shù)據(jù)值
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("請(qǐng)求參數(shù)中包含特殊字符");
}
}
else{
if(UrlFilter.checkSpecials(httpServletRequest)){
throw new Exception("請(qǐng)求的數(shù)據(jù)中包含特殊字符 ");
}
}
}
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 {
}
}到此這篇關(guān)于springboot項(xiàng)目攔截前端請(qǐng)求中的特殊字符串的文章就介紹到這了,更多相關(guān)springboot攔截特殊字符串內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何從eureka獲取服務(wù)的ip和端口號(hào)進(jìn)行Http的調(diào)用
這篇文章主要介紹了如何從eureka獲取服務(wù)的ip和端口號(hào)進(jìn)行Http的調(diào)用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
一文教你利用Stream?API批量Mock數(shù)據(jù)的方法
在日常開發(fā)的過程中我們經(jīng)常會(huì)遇到需要mock一些數(shù)據(jù)的場景,比如說?mock?一些接口的返回或者說?mock?一些測試消息用于隊(duì)列生產(chǎn)者發(fā)送消息。本文將教你如何通過?Stream?API?批量?Mock?數(shù)據(jù),需要的可以參考一下2022-09-09
詳解SpringBoot如何實(shí)現(xiàn)多環(huán)境配置
在實(shí)際的軟件開發(fā)過程中,一個(gè)應(yīng)用程序通常會(huì)有多個(gè)環(huán)境,pring?Boot?提供了一個(gè)非常靈活和強(qiáng)大的方式來管理這些環(huán)境配置,下面就跟隨小編一起學(xué)習(xí)一下吧2023-07-07
java統(tǒng)計(jì)漢字字?jǐn)?shù)的方法示例
這篇文章主要介紹了java統(tǒng)計(jì)漢字字?jǐn)?shù)的方法,結(jié)合實(shí)例形式分析了java正則判定、字符串遍歷及統(tǒng)計(jì)相關(guān)操作技巧,需要的朋友可以參考下2017-05-05
java 查找list中重復(fù)數(shù)據(jù)實(shí)例詳解
這篇文章主要介紹了java 查找list中重復(fù)數(shù)據(jù)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01
SpringCloud Config連接git與數(shù)據(jù)庫流程分析講解
springcloud config是一個(gè)解決分布式系統(tǒng)的配置管理方案。它包含了 client和server兩個(gè)部分,server端提供配置文件的存儲(chǔ)、以接口的形式將配置文件的內(nèi)容提供出去,client端通過接口獲取數(shù)據(jù)、并依據(jù)此數(shù)據(jù)初始化自己的應(yīng)用2022-12-12
Reactor定制一個(gè)生產(chǎn)的WebClient實(shí)現(xiàn)示例
這篇文章主要為大家介紹了Reactor定制一個(gè)生產(chǎn)的WebClient實(shí)現(xiàn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08

