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);
- @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 { // 针对结合的处理
- @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;
- }
- }
对于以上的配置Controller接收参数需要加@RequestBody。
测试
过滤后的数据
自定义RequestBodyAdvice过滤Json表情符号
- /**
- * @Author: ZhiHao
- * @Date: 2021/6/4 19:03
- * @Description: 过滤表情符号, POST-json请求
- * @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("过滤表情异常:{}", 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));
- }
- }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。
原文链接:https://blog.csdn.net/niugang0920/article/details/80679096