/** * Copyright © 2019, Glodon Digital Supplier BU. * <p> * All Rights Reserved. */ package com.gyoomi.adam.core.filter; import com.gyoomi.adam.core.BaseController; import com.gyoomi.adam.core.CHERRY; import com.gyoomi.adam.core.model.Response; import com.gyoomi.adam.core.properties.AdamProperties; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.util.AntPathMatcher; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; /** * Csrf攻防Filter * * @author Leon * @date 2019-10-22 16:10 */ public class CsrfFilter implements Filter { /** * Logger */ private final Logger lg = LoggerFactory.getLogger(this.getClass()); @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException { if (isExclusives((HttpServletRequest) req) || checkCsrfToken(req)) { filterChain.doFilter(req, resp); } else { lg.warn("无效的CSRF参数:{}", ((HttpServletRequest) req).getRequestURI()); Response response = Response.builder().code(HttpServletResponse.SC_SERVICE_UNAVAILABLE).msg("无效的CSRF参数").build(); BaseController.writeJsonResponse(response, (HttpServletResponse) resp); } } /** * 检查CSRF Token * * @param req ServletRequest */ private boolean checkCsrfToken(ServletRequest req) { AdamProperties adamProperties = CHERRY.SPRING_CONTEXT.getBean(AdamProperties.class); boolean isValid = false; String csrf = ((HttpServletRequest) req).getHeader(adamProperties.getCsrf().getHeaderName()); if (StringUtils.isBlank(csrf)) { csrf = req.getParameter(adamProperties.getCsrf().getRequestName()); } if (StringUtils.isNotBlank(csrf)) { Boolean hasKey = CHERRY.SPRING_CONTEXT.getBean(StringRedisTemplate.class).hasKey(CHERRY.REDIS_KEY_CSRF + csrf); isValid = hasKey == null ? false : hasKey; } return isValid; } /** * 过滤非认证URL * <p>和Spring Security的白名单类似</p> * * @param request req * @return 返回结果 */ private boolean isExclusives(HttpServletRequest request) { List<String> exclusivePath = CHERRY.SPRING_CONTEXT.getBean(AdamProperties.class).getSecurity().getExclusivePath(); AntPathMatcher antPathMatcher = new AntPathMatcher(); String requestURI = request.getRequestURI(); for (String exclusive : exclusivePath) { if (antPathMatcher.match(exclusive, requestURI)) { return true; } } return false; } }