Springboot敏感词过滤及特殊字符过滤处理

2021-06-29 15:40:11 浏览数 (7370)

技术采用的是 SpringBoot ,请求方法主要为 POST,交付测试人员进行测试,测试人员在对模糊搜索模块进行了各种特殊字符的搜索,以至于敏感词和特殊字符均会入库,那么 springboot 敏感词过滤及特殊字符过滤处理要如何实现呢?

  1. @ControllerAdvice(basePackages = "com.my")

的方式,对用户提交的数据做处理。

以下是示例代码,不影响笔者要言表的功能实现:

  1. /**
  2. * @author Ryan
  3. * @date 2019/4/25 18:41
  4. */
  5. @ControllerAdvice(basePackages = "com.ytkj")
  6. public class EscapeSensitiveWordFilter implements RequestBodyAdvice {
  7. @Override
  8. public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
  9. return true;
  10. }
  11. @Override
  12. public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
  13. return inputMessage;
  14. }
  15. @Override
  16. public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
  17. if(o != null){
  18. SensitiveWordUtils.apply(o);
  19. }
  20. return o;
  21. }
  22. @Override
  23. public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
  24. return o;
  25. }
  26. }

由于我们主要针对提交的数据做处理,主要入口在 SensitiveWordUtils.apply(o); 这里的 “Object ” 参数,其实也就是我们 Controller 方法参数中,打了 @RequestBody 的实体。我们可以直接在这里,使用一些手段做处理即可。

这里的手段,也只能使用反射了(如果读者有什么好的方案可以告诉我)。

1. 字符串替换;

2. 自定义抛出运行时异常;

这样做的另外一个好处就是,可以在这里统一管理敏感词。

如果你使用 replaceAll 的话,统一管理上就比较费劲了。

最后,笔者把自己写的反射放在下面,仅供参考,敏感词替换部分写了一个“测试“ 作为要替换入口的标记。

欢迎各界大佬来扶正!

  1. import java.lang.reflect.Field;
  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import java.util.List;
  5. import java.util.Map;
  6. /**
  7. * @author Ryan
  8. * @date 2019/4/26 12:40
  9. */
  10. public class SensitiveWordUtils {
  11. /**
  12. * @param result
  13. * @return
  14. */
  15. public static Object apply(Object result) {
  16. if (result == null) {
  17. return null;
  18. }
  19. objectParse(result);
  20. return result;
  21. }
  22. /**
  23. * @param obj
  24. */
  25. public static void objectParse(Object obj) {
  26. List<Field> allField = findAllField(obj);
  27. for (Field field : allField) {
  28. field.setAccessible(true);
  29. Class<?> typeClazz = field.getType();
  30. matchFieldType(obj, field, typeClazz);
  31. }
  32. }
  33. public static List<Field> findAllField(Object object){
  34. List<Field> result = new ArrayList<>();
  35. Class<?> clazz = object.getClass();
  36. while (true) {
  37. clazz = clazz.getSuperclass();
  38. if (clazz == Object.class) {
  39. break;
  40. }
  41. Field[] declaredFields = clazz.getDeclaredFields();
  42. result.addAll(Arrays.asList(declaredFields));
  43. }
  44. return result;
  45. }
  46. /**
  47. * @param obj
  48. * @param field
  49. * @param clazz
  50. */
  51. public static <T> void matchFieldType(Object obj, Field field, T clazz) {
  52. try {
  53. T param = (T) field.get(obj);
  54. if(param == null){
  55. return;
  56. }
  57. if (clazz == List.class) {
  58. List p = (List)param;
  59. for (Object o : p) {
  60. objectParse(o);
  61. }
  62. } else if (clazz == String.class) {
  63. setValue(obj, field, "测试");
  64. } else if (clazz == Map.class) {
  65. Map map = (Map)param;
  66. for (Object o : map.keySet()) {
  67. objectParse(o);
  68. }
  69. }
  70. } catch (IllegalAccessException e) {
  71. e.printStackTrace();
  72. }
  73. }
  74. /**
  75. *
  76. * @param object
  77. * @param field
  78. * @param param
  79. * @throws IllegalAccessException
  80. */
  81. public static void setValue(Object object, Field field, Object param) throws IllegalAccessException {
  82. if(!field.isAccessible()){
  83. throw new IllegalAccessException("modify the field fail.");
  84. }
  85. field.set(object, param);
  86. }
  87. }

这里的 SensitiveWordUtils 还有很大的优化点,我在这里没有目前只是看看效果,写的很粗糙,望大神不要喷。

读者自行实现一下,我说一下优化点:

1. 缓存 object 的 String.class 类型的 Field 或者 methodName; 在第一次加载的时候,缓存进去;放到 ConcurrentHashMap<ObjectType, List<StringField>> , 是不是感觉清爽了好多;

2. 过滤出来 String 类型的 Field ,其他的类型酌情考虑;

3. 等臣妾的再想想;

Spring Boot 统一敏感词过滤 demo

对象序列化前的处理

例如springframework框架(responseBody)json 格式:

  1. org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyAdviceChain#beforeBodyWrite

中进行对象数据的转换。

  1. @ControllerAdvice
  2. @Slf4j
  3. public class ShanDongShengYuHandler implements ResponseBodyAdvice {
  4. @Autowired
  5. private ObjectMapper objectMapper;
  6. @Override
  7. public boolean supports(MethodParameter returnType, Class converterType) {
  8. return true;
  9. }
  10.  
  11. @Override
  12. public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
  13. ResponseData d = new ResponseData();
  14. sensitiveHidden(body);
  15. d.setData(body);
  16. return d;
  17. }
  18.  
  19. /**
  20. * 只支持自定义类型数据的敏感词过滤,考虑递归性能
  21. */
  22. private void sensitiveHidden(Object body) {
  23. if(body==null || StringUtils.isBlank(body.getClass().getName()) || !body.getClass().getName().contains("山东")){
  24. return;
  25. }
  26. Field[] declaredFields = body.getClass().getDeclaredFields();
  27. for (Field declaredField : declaredFields) {
  28. SensitiveWorldHidden annotation = declaredField.getAnnotation(SensitiveWorldHidden.class);
  29. log.warn("【注解类型】{}",annotation);
  30. try {
  31. declaredField.setAccessible(true);
  32. Object o = declaredField.get(body);
  33. if(annotation != null) {
  34. String content = objectMapper.writeValueAsString(o);
  35. content = content.replace("垃圾", "**");
  36. Object replaced = objectMapper.readValue(content, o.getClass());
  37. declaredField.set(body, replaced);
  38. }else {
  39. sensitiveHidden(o);
  40. }
  41. } catch (IllegalAccessException e) {
  42. e.printStackTrace();
  43. } catch (JsonProcessingException e) {
  44. e.printStackTrace();
  45. } catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }
  50. }

 springboot 敏感词过滤及特殊字符过滤处理要如何实现就位大家分享到这里了。