RequestBodyAdvice对Http请求非法字符过滤
利用RequestBodyAdvice对HTTP请求参数放入body中的参数进行非法字符过滤。
要求: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:解释 * 允许在将请求的主体读取和转换成一个对象之前对请求进行自定义, * 并允许在将其传递到控制器方法作为一个@RequestBody或HttpEntity方法参数之前处理结果对象。 * * @author niugang * */@ControllerAdvice(basePackages = "com.niugang")public class MyRequestBodyAdvice implements RequestBodyAdvice {private final static Logger logger = LoggerFactory.getLogger(MyRequestBodyAdvice.class); @Overridepublic boolean supports(MethodParameter methodParameter, Type targetType,Class<? extends HttpMessageConverter<?>> converterType) {return true;}@Overridepublic Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {return body;} @Overridepublic 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; }}@Overridepublic 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 { // 针对结合的处理@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");} @Overridepublic InputStream getBody() throws IOException {return body;} @Overridepublic 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;}}
对于以上的配置Controller接收参数需要加@RequestBody。
测试
过滤后的数据
自定义RequestBodyAdvice过滤Json表情符号
/** * @Author: ZhiHao * @Date: 2021/6/4 19:03 * @Description: 过滤表情符号, POST-json请求 * @Versions 1.0 **/@ControllerAdvice@Slf4jpublic 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("过滤表情异常:{}", 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; } /** * 过滤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(); } /** * 检测是否有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)) { //判断到了这里表明,确认有表情字符 return true; } } return false; } /** * 判断是否为非Emoji字符 * * @param codePoint 比较的单个字符 * @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)); }}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
人的一生是奋斗的一生,人们为了取得成功都在不断地努力着,