java配置多个过滤器优先级以及几个常用过滤器操作
目录
- 过滤器配置:
- 常用过滤器之一:
- 常用过滤器之二:
- 敏感词过滤工具类
一个项目中不出意外的话会有两个以上的过滤器,但是直接不配置的话他会按照你的过滤器名字排序执行,这样的话可能会导致一些性能上或者逻辑上的问题。那么,控制一下执行顺序是我们所必须要做的。
java封装了一个FilterRegistrationBean对象,可以把他比作一个容器,将过滤器套入这个对象中,可以对这个对象进行优先级设置、过滤规则设置等属性,下面是几个常用的过滤器以及过滤器配置。
过滤器配置:
package cn.ask.filter; import javax.servlet.DispatcherType; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.DelegatingFilterProxy; /** * Title: FilterConfig * @date 2018年10月25日 * @version V1.0 * Description: 过滤器配置 */ @SuppressWarnings("all") @Configuration public class FilterConfig { /** * @Description 防xss攻击过滤器 * @date 2018年8月16日下午4:55:44 */ @Bean public FilterRegistrationBean xssFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setDispatcherTypes(DispatcherType.REQUEST); registration.setFilter(new XssFilter()); registration.addUrlPatterns("/*"); registration.setName("xssFilter"); //order数字越小越先执行 registration.setOrder(1); return registration; } /** * @Description 获取登录信息 * @date 2018年10月25日上午9:14:48 */ @Bean public FilterRegistrationBean cookieRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setDispatcherTypes(DispatcherType.REQUEST); registration.setFilter(new CookieFilter()); registration.addUrlPatterns("/*"); registration.setName("firstFilter"); registration.setOrder(2); return registration; } }
常用过滤器之一:
sso单点登录(使用cookie记录跨站数据)
package cn.ask.filter; import java.io.IOException; import java.net.URLDecoder; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; /** * Servlet Filter implementation class FirstFilter */ public class CookieFilter implements Filter { /** * Default constructor. */ public CookieFilter() { // TODO Auto-generated constructor stub } /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String tokenHeader = req.getHeader("token"); if(StringUtils.isBlank(tokenHeader)) { Cookie[] cookies = req.getCookies(); if (cookies != null && cookies.length > 0) { for (int i = 0; i < cookies.length; i++) { String name = cookies[i].getName(); String value = cookies[i].getValue(); if ("user_accesstoken".equals(name)) { // 用户token req.setAttribute("token", URLDecoder.decode(value, "utf-8")); } if ("user_avatar".equals(name)) { // 头像 req.setAttribute("avatar", URLDecoder.decode(value, "utf-8")); } if ("user_nickname".equals(name)) { // 昵称 req.setAttribute("nickname", URLDecoder.decode(value, "utf-8")); } String token = (String) req.getAttribute("token"); if (StringUtils.isBlank(token)) { req.setAttribute("isLogin", "no"); } else { req.setAttribute("isLogin", "yes"); } } }else { req.removeAttribute("token"); req.removeAttribute("avatar"); req.removeAttribute("nickname"); req.setAttribute("isLogin", "no"); } } else { req.setAttribute("token", tokenHeader); } chain.doFilter(request, response); } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } }
常用过滤器之二:
xss过滤以及防html注入过滤(包括过滤敏感词)
package cn.ask.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; /** * Title: XssFilter * @date 2018年8月16日 * @version V1.0 * Description: xss过滤 */ public class XssFilter implements Filter { @Override public void init(FilterConfig config) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); chain.doFilter(xssRequest, response); } @Override public void destroy() { } }
package cn.ask.filter; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; /** * Title: XssHttpServletRequestWrapper * @date 2018年8月16日 * @version V1.0 * Description: XSS过滤处理 */ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { /**没被包装过的HttpServletRequest(特殊场景,需要自己过滤*/ HttpServletRequest orgRequest; /**html过滤*/ private final static HtmlFilter HTMLFILTER = new HtmlFilter(); public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); orgRequest = request; } @Override public ServletInputStream getInputStream() throws IOException { //非json类型,直接返回 if(!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)){ return super.getInputStream(); } //为空,直接返回 String json = IOUtils.toString(super.getInputStream(), "utf-8"); if (StringUtils.isBlank(json)) { return super.getInputStream(); } //xss过滤 json = xssEncode(json); final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes()); return new ServletInputStream() { @Override public boolean isFinished() { return true; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() throws IOException { return bis.read(); } }; } @Override public String getParameter(String name) { String value = super.getParameter(xssEncode(name)); if (StringUtils.isNotBlank(value)) { value = xssEncode(value); } return value; } @Override public String[] getParameterValues(String name) { String[] parameters = super.getParameterValues(name); if (parameters == null || parameters.length == 0) { return null; } for (int i = 0; i < parameters.length; i++) { parameters[i] = xssEncode(parameters[i]); } return parameters; } @Override public Map<String,String[]> getParameterMap() { Map<String,String[]> map = new LinkedHashMap<>(); Map<String,String[]> parameters = super.getParameterMap(); for (String key : parameters.keySet()) { String[] values = parameters.get(key); for (int i = 0; i < values.length; i++) { values[i] = xssEncode(values[i]); } map.put(key, values); } return map; } @Override public String getHeader(String name) { String value = super.getHeader(xssEncode(name)); if (StringUtils.isNotBlank(value)) { value = xssEncode(value); } return value; } //富文本内容放行 private String xssEncode(String input) { if(!input.startsWith("<p")&&!input.startsWith("<ol")&&!input.startsWith("<ul")&&!input.startsWith("<hr/>")) { input=HTMLFILTER.filter(input); } //敏感词过滤 input=SensitiveWordUtils.getSensitiveWordUtils().replaceSensitiveWord(input, '*', 2); return input; } /** * 获取最原始的request */ public HttpServletRequest getOrgRequest() { return orgRequest; } /** * 获取最原始的request */ public static HttpServletRequest getOrgRequest(HttpServletRequest request) { if (request instanceof XssHttpServletRequestWrapper) { return ((XssHttpServletRequestWrapper) request).getOrgRequest(); } return request; } }
package cn.ask.filter; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Title: HTMLFilter * @date 2018年8月16日 * @version V1.0 * Description: 防html注入 */ public final class HtmlFilter { /** regex flag union representing /si modifiers in php **/ private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL); private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); private static final Pattern P_END_ARROW = Pattern.compile("^>"); private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); private static final Pattern P_AMP = Pattern.compile("&"); private static final Pattern P_QUOTE = Pattern.compile("<"); private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); private static final String SS="#//"; /** @xxx could grow large... maybe use sesat's ReferenceMap */ private static final ConcurrentMap<String,Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>(); private static final ConcurrentMap<String,Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>(); /** set of allowed html elements, along with allowed attributes for each element **/ private final Map<String, List<String>> vAllowed; /** counts of open tags for each (allowable) html element **/ private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>(); /** html elements which must always be self-closing (e.g. "<img />") **/ private final String[] vSelfClosingTags; /** html elements which must always have separate opening and closing tags (e.g. "<b></b>") **/ private final String[] vNeedClosingTags; /** set of disallowed html elements **/ private final String[] vDisallowed; /** attributes which should be checked for valid protocols **/ private final String[] vProtocolAtts; /** allowed protocols **/ private final String[] vAllowedProtocols; /** tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />") **/ private final String[] vRemoveBlanks; /** entities allowed within html markup **/ private final String[] vAllowedEntities; /** flag determining whether comments are allowed in input String. */ private final boolean stripComment; private final boolean encodeQuotes; private boolean vDebug = false; /** * flag determining whether to try to make tags when presented with "unbalanced" * angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false, * unbalanced angle brackets will be html escaped. */ private final boolean alwaysMakeTags; /** Default constructor. * */ public HtmlFilter() { vAllowed = new HashMap<>(); final ArrayList<String> aAtts = new ArrayList<String>(); aAtts.add("href"); aAtts.add("target"); vAllowed.put("a", aAtts); final ArrayList<String> imgAtts = new ArrayList<String>(); imgAtts.add("src"); imgAtts.add("width"); imgAtts.add("height"); imgAtts.add("alt"); vAllowed.put("img", imgAtts); final ArrayList<String> noAtts = new ArrayList<String>(); vAllowed.put("b", noAtts); vAllowed.put("strong", noAtts); vAllowed.put("i", noAtts); vAllowed.put("em", noAtts); vSelfClosingTags = new String[]{"img"}; vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; vDisallowed = new String[]{}; /**no ftp*/ vAllowedProtocols = new String[]{"http", "mailto", "https"}; vProtocolAtts = new String[]{"src", "href"}; vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; stripComment = true; encodeQuotes = true; alwaysMakeTags = true; } /** Set debug flag to true. Otherwise use default settings. See the default constructor. * * @param debug turn debug on with a true argument */ public HtmlFilter(final boolean debug) { this(); vDebug = debug; } /** Map-parameter configurable constructor. * * @param conf map containing configuration. keys match field names. */ @SuppressWarnings("unchecked") public HtmlFilter(final Map<String,Object> conf) { assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed")); vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); vDisallowed = (String[]) conf.get("vDisallowed"); vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); vProtocolAtts = (String[]) conf.get("vProtocolAtts"); vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); vAllowedEntities = (String[]) conf.get("vAllowedEntities"); stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; } private void reset() { vTagCounts.clear(); } private void debug(final String msg) { if (vDebug) { Logger.getAnonymousLogger().info(msg); } } //--------------------------------------------------------------- /**my versions of some PHP library functions*/ public static String chr(final int decimal) { return String.valueOf((char) decimal); } public static String htmlSpecialChars(final String s) { String result = s; result = regexReplace(P_AMP, "&", result); result = regexReplace(P_QUOTE, """, result); result = regexReplace(P_LEFT_ARROW, "<", result); result = regexReplace(P_RIGHT_ARROW, ">", result); return result; } //--------------------------------------------------------------- /** * given a user submitted input String, filter out any invalid or restricted * html. * * @param input text (i.e. submitted by a user) than may contain html * @return "clean" version of input, with only valid, whitelisted html elements allowed */ public String filter(final String input) { reset(); String s = input; debug("************************************************"); debug(" INPUT: " + input); s = escapeComments(s); debug(" escapeComments: " + s); s = balanceHTML(s); debug(" balanceHTML: " + s); s = checkTags(s); debug(" checkTags: " + s); s = processRemoveBlanks(s); debug("processRemoveBlanks: " + s); s = validateEntities(s); debug(" validateEntites: " + s); debug("************************************************\n\n"); return s; } public boolean isAlwaysMakeTags(){ return alwaysMakeTags; } public boolean isStripComments(){ return stripComment; } private String escapeComments(final String s) { final Matcher m = P_COMMENTS.matcher(s); final StringBuffer buf = new StringBuffer(); if (m.find()) { /**(.*?)*/ final String match = m.group(1); m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->")); } m.appendTail(buf); return buf.toString(); } private String balanceHTML(String s) { if (alwaysMakeTags) { // // try and form html // s = regexReplace(P_END_ARROW, "", s); s = regexReplace(P_BODY_TO_END, "<$1>", s); s = regexReplace(P_XML_CONTENT, "$1<$2", s); } else { // // escape stray brackets // s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); // // the last regexp causes '<>' entities to appear // (we need to do a lookahead assertion so that the last bracket can // be used in the next pass of the regexp) // s = regexReplace(P_BOTH_ARROWS, "", s); } return s; } private String checkTags(String s) { Matcher m = P_TAGS.matcher(s); final StringBuffer buf = new StringBuffer(); while (m.find()) { String replaceStr = m.group(1); replaceStr = processTag(replaceStr); m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); } m.appendTail(buf); s = buf.toString(); // these get tallied in processTag // (remember to reset before subsequent calls to filter method) for (String key : vTagCounts.keySet()) { for (int ii = 0; ii < vTagCounts.get(key); ii++) { s += "</" + key + ">"; } } return s; } private String processRemoveBlanks(final String s) { String result = s; for (String tag : vRemoveBlanks) { if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){ P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">")); } result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){ P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); } result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); } return result; } private static String regexReplace(final Pattern regexPattern, final String replacement, final String s) { Matcher m = regexPattern.matcher(s); return m.replaceAll(replacement); } private String processTag(final String s) { // ending tags Matcher m = P_END_TAG.matcher(s); if (m.find()) { final String name = m.group(1).toLowerCase(); if (allowed(name)) { if (!inArray(name, vSelfClosingTags)) { if (vTagCounts.containsKey(name)) { vTagCounts.put(name, vTagCounts.get(name) - 1); return "</" + name + ">"; } } } } // starting tags m = P_START_TAG.matcher(s); if (m.find()) { final String name = m.group(1).toLowerCase(); final String body = m.group(2); String ending = m.group(3); //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); if (allowed(name)) { String params = ""; final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); final List<String> paramNames = new ArrayList<String>(); final List<String> paramValues = new ArrayList<String>(); while (m2.find()) { /**([a-z0-9]+)*/ paramNames.add(m2.group(1)); /**(.*?)*/ paramValues.add(m2.group(3)); } while (m3.find()) { /**([a-z0-9]+)*/ paramNames.add(m3.group(1)); /**([^\"\\s']+)*/ paramValues.add(m3.group(3)); } String paramName, paramValue; for (int ii = 0; ii < paramNames.size(); ii++) { paramName = paramNames.get(ii).toLowerCase(); paramValue = paramValues.get(ii); if (allowedAttribute(name, paramName)) { if (inArray(paramName, vProtocolAtts)) { paramValue = processParamProtocol(paramValue); } params += " " + paramName + "=\"" + paramValue + "\""; } } if (inArray(name, vSelfClosingTags)) { ending = " /"; } if (inArray(name, vNeedClosingTags)) { ending = ""; } if (ending == null || ending.length() < 1) { if (vTagCounts.containsKey(name)) { vTagCounts.put(name, vTagCounts.get(name) + 1); } else { vTagCounts.put(name, 1); } } else { ending = " /"; } return "<" + name + params + ending + ">"; } else { return ""; } } // comments m = P_COMMENT.matcher(s); if (!stripComment && m.find()) { return "<" + m.group() + ">"; } return ""; } private String processParamProtocol(String s) { s = decodeEntities(s); final Matcher m = P_PROTOCOL.matcher(s); if (m.find()) { final String protocol = m.group(1); if (!inArray(protocol, vAllowedProtocols)) { // bad protocol, turn into local anchor link instead s = "#" + s.substring(protocol.length() + 1, s.length()); if (s.startsWith(SS)) { s = "#" + s.substring(3, s.length()); } } } return s; } private String decodeEntities(String s) { StringBuffer buf = new StringBuffer(); Matcher m = P_ENTITY.matcher(s); while (m.find()) { final String match = m.group(1); final int decimal = Integer.decode(match).intValue(); m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); } m.appendTail(buf); s = buf.toString(); buf = new StringBuffer(); m = P_ENTITY_UNICODE.matcher(s); while (m.find()) { final String match = m.group(1); final int decimal = Integer.valueOf(match, 16).intValue(); m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); } m.appendTail(buf); s = buf.toString(); buf = new StringBuffer(); m = P_ENCODE.matcher(s); while (m.find()) { final String match = m.group(1); final int decimal = Integer.valueOf(match, 16).intValue(); m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); } m.appendTail(buf); s = buf.toString(); s = validateEntities(s); return s; } private String validateEntities(final String s) { StringBuffer buf = new StringBuffer(); // validate entities throughout the string Matcher m = P_VALID_ENTITIES.matcher(s); while (m.find()) { /**([^&;]*)*/ final String one = m.group(1); /**(?=(;|&|$))*/ final String two = m.group(2); m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); } m.appendTail(buf); return encodeQuotes(buf.toString()); } private String encodeQuotes(final String s){ if(encodeQuotes){ StringBuffer buf = new StringBuffer(); Matcher m = P_VALID_QUOTES.matcher(s); while (m.find()) { /**(>|^)*/ final String one = m.group(1); /**([^<]+?)*/ final String two = m.group(2); /**(<|$)*/ final String three = m.group(3); m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three)); } m.appendTail(buf); return buf.toString(); }else{ return s; } } private String checkEntity(final String preamble, final String term) { return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble; } private boolean isValidEntity(final String entity) { return inArray(entity, vAllowedEntities); } private static boolean inArray(final String s, final String[] array) { for (String item : array) { if (item != null && item.equals(s)) { return true; } } return false; } private boolean allowed(final String name) { return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); } private boolean allowedAttribute(final String name, final String paramName) { return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); } }
敏感词过滤工具类
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Serializable; import java.util.*; import org.springframework.core.io.ClassPathResource; /** * Title: SensitiveWordUtils * @author: gaodeqiang * @date 2018年12月12日 * @version V1.0 * Description: 敏感词过滤 */ @SuppressWarnings("all") public class SensitiveWordUtils implements Serializable { private static final long serialVersionUID = 1L; private SensitiveWordUtils() { } private static SensitiveWordUtils sensitiveWordUtils = null; public synchronized static SensitiveWordUtils getSensitiveWordUtils() { if (sensitiveWordUtils == null) { sensitiveWordUtils = new SensitiveWordUtils(); } return sensitiveWordUtils; } private static Set<String> sensitiveWordSet = null; static { try { readResource("keywords.txt"); } catch (Exception e) { e.printStackTrace(); } // 初始化敏感词库 initSensitiveWordMap(); } private static final int MinMatchTYpe = 1; // 最小匹配规则,如:敏感词库["中国","中国人"],语句:"我是中国人",匹配结果:我是[中国]人 private static final int MaxMatchType = 2; // 最大匹配规则,如:敏感词库["中国","中国人"],语句:"我是中国人",匹配结果:我是[中国人] private static HashMap sensitiveWordMap = new HashMap<>(); /** * @author gaodeqiang * @Description 读取资源文件 * @date 2018年12月13日上午9:29:01 */ private static void readResource(String name) throws Exception { ClassPathResource resource = new ClassPathResource(name); InputStream inputStream = resource.getInputStream(); InputStreamReader read = new InputStreamReader(inputStream, "utf-8"); // 初始化set集合 sensitiveWordSet = new HashSet<String>(); // 缓冲区读取流 BufferedReader bufferedReader = new BufferedReader(read); // 循环读取文件中内容,每次读取一行内容 String txt = null; while ((txt = bufferedReader.readLine()) != null) { // 读取文件,将文件内容放入到set中 sensitiveWordSet.add(txt); } read.close(); } /** * @author gaodeqiang * @Description 初始化敏感词库,构建DFA算法模型 * @date 2018年12月13日上午9:30:08 */ private static void initSensitiveWordMap() { // 初始化敏感词容器,减少扩容操作 sensitiveWordMap = new HashMap(sensitiveWordSet.size()); String key; Map nowMap; Map<String, String> newWorMap; // 迭代sensitiveWordSet Iterator<String> iterator = sensitiveWordSet.iterator(); while (iterator.hasNext()) { // 关键字 key = iterator.next(); nowMap = sensitiveWordMap; for (int i = 0; i < key.length(); i++) { // 转换成char型 char keyChar = key.charAt(i); // 库中获取关键字 Object wordMap = nowMap.get(keyChar); // 如果存在该key,直接赋值,用于下一个循环获取 if (wordMap != null) { nowMap = (Map) wordMap; } else { // 不存在则,则构建一个map,同时将isEnd设置为0,因为他不是最后一个 newWorMap = new HashMap<>(); // 不是最后一个 newWorMap.put("isEnd", "0"); nowMap.put(keyChar, newWorMap); nowMap = newWorMap; } if (i == key.length() - 1) { // 最后一个 nowMap.put("isEnd", "1"); } } } } /** * @author gaodeqiang * @Description 检查文字中是否包含敏感字符 * @date 2018年12月13日上午9:38:35 */ private int checkSensitiveWord(String txt, int beginIndex, int matchType) { // 敏感词结束标识位:用于敏感词只有1位的情况 boolean flag = false; // 匹配标识数默认为0 int matchFlag = 0; char word; Map nowMap = sensitiveWordMap; for (int i = beginIndex; i < txt.length(); i++) { word = txt.charAt(i); // 获取指定key nowMap = (Map) nowMap.get(word); if (nowMap != null) {// 存在,则判断是否为最后一个 // 找到相应key,匹配标识+1 matchFlag++; // 如果为最后一个匹配规则,结束循环,返回匹配标识数 if ("1".equals(nowMap.get("isEnd"))) { // 结束标志位为true flag = true; // 最小规则,直接返回,最大规则还需继续查找 if (MinMatchTYpe == matchType) { break; } } } else {// 不存在,直接返回 break; } } if (matchFlag < 2 || !flag) {// 长度必须大于等于1,为词 matchFlag = 0; } return matchFlag; } /** * @author gaodeqiang * @Description 判断文字是否包含敏感字符 匹配规则 1:最小匹配规则,2:最大匹配规则 * @date 2018年12月13日上午9:34:23 */ public boolean contains(String txt, int matchType) { boolean flag = false; for (int i = 0; i < txt.length(); i++) { int matchFlag = checkSensitiveWord(txt, i, matchType); // 判断是否包含敏感字符 if (matchFlag > 0) { // 大于0存在,返回true flag = true; } } return flag; } /** * @author gaodeqiang * @Description 获取文字中的敏感词 * @date 2018年12月13日上午9:36:00 */ public Set<String> getSensitiveWord(String txt, int matchType) { Set<String> sensitiveWordList = new HashSet<>(); for (int i = 0; i < txt.length(); i++) { // 判断是否包含敏感字符 int length = checkSensitiveWord(txt, i, matchType); if (length > 0) {// 存在,加入list中 sensitiveWordList.add(txt.substring(i, i + length)); i = i + length - 1;// 减1的原因,是因为for会自增 } } return sensitiveWordList; } /** * @author gaodeqiang * @Description 替换敏感字字符 * @date 2018年12月13日上午9:36:34 */ public String replaceSensitiveWord(String txt, char replaceChar, int matchType) { String resultTxt = txt; // 获取所有的敏感词 Set<String> set = getSensitiveWord(txt, matchType); Iterator<String> iterator = set.iterator(); String word; String replaceString; while (iterator.hasNext()) { word = iterator.next(); replaceString = getReplaceChars(replaceChar, word.length()); resultTxt = resultTxt.replaceAll(word, replaceString); } return resultTxt; } /** * @author gaodeqiang * @Description 获取替换字符串 * @date 2018年12月13日上午9:37:53 */ private String getReplaceChars(char replaceChar, int length) { String resultReplace = String.valueOf(replaceChar); for (int i = 1; i < length; i++) { resultReplace += replaceChar; } return resultReplace; } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。
赞 (0)