使用RequestBodyAdvice實(shí)現(xiàn)對(duì)Http請(qǐng)求非法字符過(guò)濾
RequestBodyAdvice對(duì)Http請(qǐng)求非法字符過(guò)濾
利用RequestBodyAdvice對(duì)HTTP請(qǐng)求參數(shù)放入body中的參數(shù)進(jìn)行非法字符過(guò)濾。
要求:spring 4.2+
額外的pom.xml
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.44</version> </dependency>
代碼
package com.niugang.controller;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
/**
* RequestBodyAdvice:解釋
* 允許在將請(qǐng)求的主體讀取和轉(zhuǎn)換成一個(gè)對(duì)象之前對(duì)請(qǐng)求進(jìn)行自定義,
* 并允許在將其傳遞到控制器方法作為一個(gè)@RequestBody或HttpEntity方法參數(shù)之前處理結(jié)果對(duì)象。
*
* @author niugang
*
*/
@ControllerAdvice(basePackages = "com.niugang")
public class MyRequestBodyAdvice implements RequestBodyAdvice {
private final static Logger logger = LoggerFactory.getLogger(MyRequestBodyAdvice.class);
@Override
public boolean supports(MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
try {
return new MyHttpInputMessage(inputMessage);
} catch (Exception e) {
e.printStackTrace();
return inputMessage;
}
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
class MyHttpInputMessage implements HttpInputMessage {
private HttpHeaders headers;
private InputStream body;
@SuppressWarnings("unchecked")
public MyHttpInputMessage(HttpInputMessage inputMessage) throws Exception {
String string = IOUtils.toString(inputMessage.getBody(), "UTF-8");
Map<String, Object> mapJson = (Map<String, Object>) JSON.parseObject(string, Map.class);
Map<String, Object> map = new HashMap<String, Object>();
Set<Entry<String, Object>> entrySet = mapJson.entrySet();
for (Entry<String, Object> entry : entrySet) {
String key = entry.getKey();
Object objValue = entry.getValue();
if (objValue instanceof String) {
String value = objValue.toString();
map.put(key, filterDangerString(value));
} else { // 針對(duì)結(jié)合的處理
@SuppressWarnings("rawtypes")
List<HashMap> parseArray = JSONArray.parseArray(objValue.toString(), HashMap.class);
List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
for (Map<String, Object> innerMap : parseArray) {
Map<String, Object> childrenMap = new HashMap<String, Object>();
Set<Entry<String, Object>> elseEntrySet = innerMap.entrySet();
for (Entry<String, Object> en : elseEntrySet) {
String innerKey = en.getKey();
Object innerObj = en.getValue();
if (innerObj instanceof String) {
String value = innerObj.toString();
childrenMap.put(innerKey, filterDangerString(value));
}
}
listMap.add(childrenMap);
}
map.put(key, listMap);
}
}
this.headers = inputMessage.getHeaders();
this.body = IOUtils.toInputStream(JSON.toJSONString(map), "UTF-8");
}
@Override
public InputStream getBody() throws IOException {
return body;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}
private String filterDangerString(String value) {
if (value == null) {
return null;
}
value = value.replaceAll("\\|", "");
value = value.replaceAll("&", "");
value = value.replaceAll(";", "");
value = value.replaceAll("@", "");
value = value.replaceAll("'", "");
value = value.replaceAll("\\'", "");
value = value.replaceAll("<", "");
value = value.replaceAll("-", "");
value = value.replaceAll(">", "");
value = value.replaceAll("\\(", "");
value = value.replaceAll("\\)", "");
value = value.replaceAll("\\+", "");
value = value.replaceAll("\r", "");
value = value.replaceAll("\n", "");
value = value.replaceAll("script", "");
value = value.replaceAll("select", "");
value = value.replaceAll("\"", "");
value = value.replaceAll(">", "");
value = value.replaceAll("<", "");
value = value.replaceAll("=", "");
value = value.replaceAll("/", "");
return value;
}
}
對(duì)于以上的配置Controller接收參數(shù)需要加@RequestBody。
測(cè)試

過(guò)濾后的數(shù)據(jù)

自定義RequestBodyAdvice過(guò)濾Json表情符號(hào)
/**
* @Author: ZhiHao
* @Date: 2021/6/4 19:03
* @Description: 過(guò)濾表情符號(hào), POST-json請(qǐng)求
* @Versions 1.0
**/
@ControllerAdvice
@Slf4j
public class FilterEmojiRequestBodyAdvice implements RequestBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
Annotation[] annotations = methodParameter.getParameterAnnotations();
for (Annotation ann : annotations) {
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
return true;
}
}
return false;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
return inputMessage;
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
try {
this.filterEmojiAfterBody(body);
} catch (Exception e) {
log.info("過(guò)濾表情異常:{}", e);
}
return body;
}
private void filterEmojiAfterBody(Object body) throws IllegalAccessException {
if (null != body) {
Field[] fields = ReflectUtil.getFields(body.getClass());
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (field.isAnnotationPresent(Valid.class)) {
field.setAccessible(true);
this.filterEmojiAfterBody(field.get(body));
}
if (field.isAnnotationPresent(FilterEmoji.class)) {
field.setAccessible(true);
Object value = field.get(body);
if (value instanceof String) {
String str = filterEmoji(value.toString());
field.set(body, str);
}
}
}
}
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
/**
* 過(guò)濾emoji 或者 其他非文字類型的字符
*
* @param source
* @return
*/
public static String filterEmoji(String source) {
if (StringUtils.isEmpty(source)) {
return "";
}
if (!containsEmoji(source)) {
return source;//如果不包含,直接返回
}
StringBuilder buf = new StringBuilder();
int len = source.length();
for (int i = 0; i < len; i++) {
char codePoint = source.charAt(i);
if (isNotEmojiCharacter(codePoint)) {
buf.append(codePoint);
}
}
return buf.toString().trim();
}
/**
* 檢測(cè)是否有emoji字符
*
* @param source
* @return 一旦含有就拋出
*/
public static boolean containsEmoji(String source) {
if (StringUtils.isBlank(source)) {
return false;
}
int len = source.length();
for (int i = 0; i < len; i++) {
char codePoint = source.charAt(i);
if (!isNotEmojiCharacter(codePoint)) {
//判斷到了這里表明,確認(rèn)有表情字符
return true;
}
}
return false;
}
/**
* 判斷是否為非Emoji字符
*
* @param codePoint 比較的單個(gè)字符
* @return
*/
public static boolean isNotEmojiCharacter(char codePoint) {
return (codePoint == 0x0) ||
(codePoint == 0x9) ||
(codePoint == 0xA) ||
(codePoint == 0xD) ||
((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
}
}
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java Spring數(shù)據(jù)單元配置過(guò)程解析
這篇文章主要介紹了Java Spring數(shù)據(jù)單元配置過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12
SpringSecurity?用戶帳號(hào)已被鎖定的問(wèn)題及解決方法
這篇文章主要介紹了SpringSecurity?用戶帳號(hào)已被鎖定,本文給大家分享問(wèn)題原因及解決方式,需要的朋友可以參考下2023-12-12
手動(dòng)構(gòu)建springBoot啟動(dòng)器過(guò)程圖解
這篇文章主要介紹了手動(dòng)構(gòu)建springBoot啟動(dòng)器過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
java調(diào)用百度定位api服務(wù)獲取地理位置示例
java調(diào)用百度定位api服務(wù)獲取地理位置示例,大家參考使用吧2013-12-12
Spring Boot 會(huì)員管理系統(tǒng)之處理文件上傳功能
Spring Boot會(huì)員管理系統(tǒng)的中,需要涉及到Spring框架,SpringMVC框架,Hibernate框架,thymeleaf模板引擎。這篇文章主要介紹了Spring Boot會(huì)員管理系統(tǒng)之處理文件上傳功能,需要的朋友可以參考下2018-03-03
面試題:java中為什么foreach中不允許對(duì)元素進(jìn)行add和remove
讀者遇到了一個(gè)比較經(jīng)典的面試題,也就是標(biāo)題上說(shuō)的,為什么 foreach 中不允許對(duì)元素進(jìn)行 add 和 remove,本文就詳細(xì)的介紹一下,感興趣的可以了解一下2021-10-10

