/** * Repeatable 过滤器 * * */ public class RepeatableFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest && StringUtils.equalsAnyIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) { requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); } if (null == requestWrapper) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } } @Override public void destroy() { } }
=================================
/** * 构建可重复读取inputStream的request * * */ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException { super(request); request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); body = HttpHelper.getBodyString(request).getBytes("UTF-8"); } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } }
=========================================
/** * 防止XSS攻击的过滤器 * * */ public class XssFilter implements Filter { /** * 排除链接 */ public List<String> excludes = new ArrayList<>(); /** * xss过滤开关 */ public boolean enabled = false; @Override public void init(FilterConfig filterConfig) throws ServletException { String tempExcludes = filterConfig.getInitParameter("excludes"); String tempEnabled = filterConfig.getInitParameter("enabled"); if (StringUtils.isNotEmpty(tempExcludes)) { String[] url = tempExcludes.split(","); for (int i = 0; url != null && i < url.length; i++) { excludes.add(url[i]); } } if (StringUtils.isNotEmpty(tempEnabled)) { enabled = Boolean.valueOf(tempEnabled); } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; if (handleExcludeURL(req, resp)) { chain.doFilter(request, response); return; } XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); chain.doFilter(xssRequest, response); } private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { if (!enabled) { return true; } if (excludes == null || excludes.isEmpty()) { return false; } String url = request.getServletPath(); for (String pattern : excludes) { Pattern p = Pattern.compile("^" + pattern); Matcher m = p.matcher(url); if (m.find()) { return true; } } return false; } @Override public void destroy() { } }
==============================
/** * XSS过滤处理 * * */ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { /** * @param request */ public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); } @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); if (values != null) { int length = values.length; String[] escapseValues = new String[length]; for (int i = 0; i < length; i++) { // 防xss攻击和过滤前后空格 escapseValues[i] = EscapeUtil.clean(values[i]).trim(); } return escapseValues; } return super.getParameterValues(name); } @Override public ServletInputStream getInputStream() throws IOException { // 非json类型,直接返回 if (!isJsonRequest()) { return super.getInputStream(); } // 为空,直接返回 String json = IOUtils.toString(super.getInputStream(), "utf-8"); if (StringUtils.isEmpty(json)) { return super.getInputStream(); } // xss过滤 json = EscapeUtil.clean(json).trim(); final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8")); 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(); } }; } /** * 是否是Json请求 * * @param */ public boolean isJsonRequest() { String header = super.getHeader(HttpHeaders.CONTENT_TYPE); return MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(header); } }
======================
/** * 防止重复提交拦截器 * * */ @Component public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); if (annotation != null) { if (this.isRepeatSubmit(request)) { AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult)); return false; } } return true; } else { return super.preHandle(request, response, handler); } } /** * 验证是否重复提交由子类实现具体的防重复提交的规则 * * @param request * @return * @throws Exception */ public abstract boolean isRepeatSubmit(HttpServletRequest request); }
==================================================
/** * 判断请求url和数据是否和上一次相同, * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 * * */ @Component public class SameUrlDataInterceptor extends RepeatSubmitInterceptor { public final String REPEAT_PARAMS = "repeatParams"; public final String REPEAT_TIME = "repeatTime"; // 令牌自定义标识 @Value("${token.header}") private String header; @Autowired private RedisCache redisCache; /** * 间隔时间,单位:秒 默认10秒 * * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据 */ private int intervalTime = 10; public void setIntervalTime(int intervalTime) { this.intervalTime = intervalTime; } @SuppressWarnings("unchecked") @Override public boolean isRepeatSubmit(HttpServletRequest request) { String nowParams = ""; if (request instanceof RepeatedlyRequestWrapper) { RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; nowParams = HttpHelper.getBodyString(repeatedlyRequest); } // body参数为空,获取Parameter的数据 if (StringUtils.isEmpty(nowParams)) { nowParams = JSONObject.toJSONString(request.getParameterMap()); } Map<String, Object> nowDataMap = new HashMap<String, Object>(); nowDataMap.put(REPEAT_PARAMS, nowParams); nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); // 请求地址(作为存放cache的key值) String url = request.getRequestURI(); // 唯一值(没有消息头则使用请求地址) String submitKey = request.getHeader(header); if (StringUtils.isEmpty(submitKey)) { submitKey = url; } // 唯一标识(指定key + 消息头) String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey; Object sessionObj = redisCache.getCacheObject(cache_repeat_key); if (sessionObj != null) { Map<String, Object> sessionMap = (Map<String, Object>) sessionObj; if (sessionMap.containsKey(url)) { Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url); if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap)) { return true; } } } Map<String, Object> cacheMap = new HashMap<String, Object>(); cacheMap.put(url, nowDataMap); redisCache.setCacheObject(cache_repeat_key, cacheMap, intervalTime, TimeUnit.SECONDS); return false; } /** * 判断参数是否相同 */ private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap) { String nowParams = (String) nowMap.get(REPEAT_PARAMS); String preParams = (String) preMap.get(REPEAT_PARAMS); return nowParams.equals(preParams); } /** * 判断两次间隔时间 */ private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap) { long time1 = (Long) nowMap.get(REPEAT_TIME); long time2 = (Long) preMap.get(REPEAT_TIME); if ((time1 - time2) < (this.intervalTime * 1000)) { return true; } return false; } }
==========================
/** * token过滤器 验证token有效性 * * */ @Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { @Autowired private TokenService tokenService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { LoginUser loginUser = tokenService.getLoginUser(request); if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) { tokenService.verifyToken(loginUser); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authenticationToken); } chain.doFilter(request, response); } }
==================================
/** * 认证失败处理类 返回未授权 * * */ @Component public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable { private static final long serialVersionUID = -8970718410437077606L; @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException { int code = HttpStatus.UNAUTHORIZED; String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg))); } }
=====================================================
/** * 自定义退出处理类 返回成功 * * */ @Configuration public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { @Autowired private TokenService tokenService; /** * 退出处理 * * @return */ @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { LoginUser loginUser = tokenService.getLoginUser(request); if (StringUtils.isNotNull(loginUser)) { String userName = loginUser.getUsername(); // 删除用户缓存记录 tokenService.delLoginUser(loginUser.getToken()); // 记录用户退出日志 AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功")); } ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "退出成功"))); } }