Springboot敏感詞過濾


實現方案2種

1.Springboot參數攔截 

繼承AbstractNamedValueMethodArgumentResolver

2.Springboot AOP  所有String類型的參數提交都會被驗證,替換規則參考百度

  @Around實現

package com.bysk.admin.common.filter;

import com.bysk.base.util.RedisUtils;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author: zhangyb
 * @date: 2020/11/19 9:21
 * @Description: 敏感詞過濾 只會攔截使用了Post和put請求的方法即修改和新增,感覺會影響性能,
 *              后面建議使用單獨注解實現關鍵字過濾
 * @UpdateUser : zhangyb
 * @UpdateDate :2020/11/19 9:21
 * @UpdateRemark:
 */
@Aspect
@Component
public class SensitiveWord {
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    WordFilter wordFilter;
    @Around("@annotation(org.springframework.web.bind.annotation.PostMapping)||@annotation(org.springframework.web.bind.annotation.PutMapping)")
    @SneakyThrows
    public Object doBefore(ProceedingJoinPoint point) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        if (request.getRequestURI().contains("/word/sensitiveword")) {
            return point.proceed();
        }
        //所有的參數對象
        for (Object arg : point.getArgs()) {
            //參數對象,通過反射將String類型的值進行敏感詞過濾
            Class<?> aClass = arg.getClass();
            //遞歸遍歷,將所有String參數進行敏感詞匹配
            foundString(aClass,arg);
        }
        return  point.proceed();
    }

    /**
    * @author: zhangyb
    * @date:  2020/11/19 13:57
    * @Description: 遞歸將String替換
    * @UpdateUser : zhangyb
    * @UpdateDate :2020/11/19 13:57
    * @UpdateRemark:
    */
    @SneakyThrows
    public Class<?> foundString(Class clazz,Object arg ){
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            Class<?> type = declaredField.getType();
            if (type==String.class&&!Modifier.toString(declaredField.getModifiers()).contains("final")){
                //如果是String類型,進行關鍵詞匹配 且要排除final修飾的字段
                    declaredField.setAccessible(true);
                    String value=(String)declaredField.get(arg);
                    declaredField.set(arg, wordFilter.replaceWords(value));
            }else if (type.getPackage()!=null&&type.getPackage().getName().contains("com.bysk")){
                        Method[] methods = clazz.getMethods();
                        for (Method method : methods) {
                            String name = method.getName();
                            if (name.toLowerCase().contains("get"+declaredField.getName().toLowerCase())){
                                Object invoke = method.invoke(arg);
                                this.foundString(type,invoke);
                                break;
                            }
                        }
                    }
        }
        return  clazz;
    }
}
package com.bysk.admin.common.filter;
import com.bysk.admin.modules.word.mapper.SensitiveWordMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
/**
 * @Author: zhangyb
 * @Date: 2020/11/19 11:13
 */

/**
 * @program: 農事雲
 * @description:
 * @Author: Zhangyb
 * @CreateDate: 11:13
 * @UpdateUser:
 * @UpdateDate
 * @UpdateRemark:
 * @Version: 1.0
 */
@Slf4j
@Component
public class WordFilter {
    private final static String WORDS = "WORDS";
    private final static String REPLACE_CHAR = "*";
    private static HashMap sensitiveWordMap;
    /**     * 最小匹配規則     */
    private static int minMatchTYpe = 1;
    /**     * 最大匹配規則     */
    private static int maxMatchType = 2;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private SensitiveWordMapper sensitiveWordMapper ;

    public  String replaceWords(String text) {
        if (StringUtils.isBlank(text)) {
            return text;
        }
        List<Object> words = redisTemplate.opsForList().range("SensitiveWord", 0, -1);
        if (words.size()<=0){
            words=sensitiveWordMapper.listStr();
            //更新redis
            redisTemplate.opsForList().leftPushAll("SensitiveWord",sensitiveWordMapper.listStr());
        }
        //緩存獲取敏感詞匯原記錄
        return WordFilter.replaceSensitiveWord(words, text, WordFilter.minMatchTYpe);
    }

    /**
     * 替換敏感字字符
     *
     * @param data      敏感字集合
     * @param txt       待檢查文本
     * @param matchType 匹配規則
     */
    private static String replaceSensitiveWord(List<Object> data, String txt, int matchType) {
        if (sensitiveWordMap == null) {
            addSensitiveWord(data);
        }
        String resultTxt = txt;
        //獲取所有的敏感詞
        List<String> set = getSensitiveWord(txt, matchType);
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            resultTxt = resultTxt.replaceAll(iterator.next(), REPLACE_CHAR);
        }
        return resultTxt;
    }


    /**
     * 讀取敏感詞庫,將敏感詞放入HashSet中,構建一個DFA算法模型:
     * 說明:該方法來源於互聯網
     */
    private static void addSensitiveWord(List<Object> datas) {
        sensitiveWordMap = new HashMap(datas.size());
        Iterator<Object> iterator = datas.iterator();
        Map<String, Object> now = null;
        Map now2 = null;
        while (iterator.hasNext()) {
            now2 = sensitiveWordMap;
            String word = (String)iterator.next(); //敏感詞
            word=word.trim();
            for (int i = 0; i < word.length(); i++) {
                char key_word = word.charAt(i);
                Object obj = now2.get(key_word);
                if (obj != null) { //存在
                    now2 = (Map) obj;
                } else { //不存在
                    now = new HashMap<String, Object>();
                    now.put("isEnd", "0");
                    now2.put(key_word, now);
                    now2 = now;
                }
                if (i == word.length() - 1) {
                    now2.put("isEnd", "1");
                }
            }
        }
    }

    /**
     * 獲取內容中的敏感詞
     *說明:該方法來源於互聯網
     * @param text      內容
     * @param matchType 匹配規則 1=不最佳匹配,2=最佳匹配
     * @return
     */
    private static List<String> getSensitiveWord(String text, int matchType) {
        List<String> words = new ArrayList<String>();
        Map now = sensitiveWordMap;
        int count = 0; //初始化敏感詞長度
        int start = 0; //標志敏感詞開始的下標
        for (int i = 0; i < text.length(); i++) {
            char key = text.charAt(i);
            now = (Map) now.get(key);
            if (now != null) { //存在
                count++;
                if (count == 1) {
                    start = i;
                }
                if ("1".equals(now.get("isEnd"))) { //敏感詞結束
                    now = sensitiveWordMap; //重新獲取敏感詞庫
                    words.add(text.substring(start, start + count)); //取出敏感詞,添加到集合
                    count = 0; //初始化敏感詞長度
                }
            } else { //不存在
                now = sensitiveWordMap;//重新獲取敏感詞庫
                if (count == 1 && matchType == 1) { //不最佳匹配
                    count = 0;
                } else if (count == 1 && matchType == 2) { //最佳匹配
                    words.add(text.substring(start, start + count));
                    count = 0;
                }
            }
        }
        return words;
    }
    public WordFilter() {
        super();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM