欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > SpringSecurity源码分析-过滤器链是如何植入到spring中的

SpringSecurity源码分析-过滤器链是如何植入到spring中的

2025/3/29 5:16:41 来源:https://blog.csdn.net/qq_43676797/article/details/140247476  浏览:    关键词:SpringSecurity源码分析-过滤器链是如何植入到spring中的

SpringSecurity源码分析-过滤器链是如何植入到spring中的

一切的源头都是因为在web.xml中配置了这样一个Filter

<!--security--><filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping>

DelegatingFilterProxy中加载FilterChainProxy

  1. 这是一个模板类,是一个过滤器链代理对象,SpringSecurity中的FilterChainProxy通过这个过滤器植入进来
  2. DelegatingFilterProxy是对外提供的,用于植入外部过滤器链的类
  3. FilterChainProxy在这个类中被植入Spring中.
public class DelegatingFilterProxy extends GenericFilterBean {@Nullableprivate String contextAttribute;@Nullableprivate WebApplicationContext webApplicationContext;@Nullableprivate String targetBeanName;private boolean targetFilterLifecycle;@Nullable/** 真实的过滤器 */private volatile Filter delegate;private final Object delegateMonitor;public DelegatingFilterProxy() {this.targetFilterLifecycle = false;this.delegateMonitor = new Object();}public DelegatingFilterProxy(Filter delegate) {this.targetFilterLifecycle = false;this.delegateMonitor = new Object();Assert.notNull(delegate, "Delegate Filter must not be null");this.delegate = delegate;}public DelegatingFilterProxy(String targetBeanName) {this(targetBeanName, (WebApplicationContext)null);}public DelegatingFilterProxy(String targetBeanName, @Nullable WebApplicationContext wac) {this.targetFilterLifecycle = false;this.delegateMonitor = new Object();Assert.hasText(targetBeanName, "Target Filter bean name must not be null or empty");this.setTargetBeanName(targetBeanName);this.webApplicationContext = wac;if (wac != null) {this.setEnvironment(wac.getEnvironment());}}public void setContextAttribute(@Nullable String contextAttribute) {this.contextAttribute = contextAttribute;}@Nullablepublic String getContextAttribute() {return this.contextAttribute;}public void setTargetBeanName(@Nullable String targetBeanName) {this.targetBeanName = targetBeanName;}@Nullableprotected String getTargetBeanName() {return this.targetBeanName;}public void setTargetFilterLifecycle(boolean targetFilterLifecycle) {this.targetFilterLifecycle = targetFilterLifecycle;}protected boolean isTargetFilterLifecycle() {return this.targetFilterLifecycle;}/** 这个方法在父类的init方法中调用,这个方法构造真实的过滤器*/protected void initFilterBean() throws ServletException {synchronized(this.delegateMonitor) {if (this.delegate == null) {if (this.targetBeanName == null) {this.targetBeanName = this.getFilterName();}WebApplicationContext wac = this.findWebApplicationContext();if (wac != null) {this.delegate = this.initDelegate(wac);}}}}public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {Filter delegateToUse = this.delegate;if (delegateToUse == null) {synchronized(this.delegateMonitor) {delegateToUse = this.delegate;if (delegateToUse == null) {WebApplicationContext wac = this.findWebApplicationContext();if (wac == null) {throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");}delegateToUse = this.initDelegate(wac);}this.delegate = delegateToUse;}}/** 调用真实过滤器中的doFilter方法*/this.invokeDelegate(delegateToUse, request, response, filterChain);}public void destroy() {Filter delegateToUse = this.delegate;if (delegateToUse != null) {this.destroyDelegate(delegateToUse);}}@Nullableprotected WebApplicationContext findWebApplicationContext() {if (this.webApplicationContext != null) {if (this.webApplicationContext instanceof ConfigurableApplicationContext) {ConfigurableApplicationContext cac = (ConfigurableApplicationContext)this.webApplicationContext;if (!cac.isActive()) {cac.refresh();}}return this.webApplicationContext;} else {String attrName = this.getContextAttribute();return attrName != null ? WebApplicationContextUtils.getWebApplicationContext(this.getServletContext(), attrName) : WebApplicationContextUtils.findWebApplicationContext(this.getServletContext());}}/** 获取过滤器链 springSecurityFilterChain*/protected Filter initDelegate(WebApplicationContext wac) throws ServletException {String targetBeanName = this.getTargetBeanName();Assert.state(targetBeanName != null, "No target bean name set");/** 根据名字和类型获取获取过滤器链,这里的targetBeanName即springSecurityFilterChain,这个是在Spring中写死的,自动装配的..*/Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class);if (this.isTargetFilterLifecycle()) {delegate.init(this.getFilterConfig());}return delegate;}protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {delegate.doFilter(request, response, filterChain);}protected void destroyDelegate(Filter delegate) {if (this.isTargetFilterLifecycle()) {delegate.destroy();}}
}

小结:通过过滤器链代理对象DelegatingFilterProxy找到真正的过滤器链FilterChainProxy,然后去一个一个的过滤器去处理请求

FilterChainProxy

  1. private List filterChains 存储过滤器链
  2. doFilter方法中调用doFilterInternal方法
  3. 获取到所有的过滤器,挨个执行filter的filter方法
public class FilterChainProxy extends GenericFilterBean {// ~ Static fields/initializers// =====================================================================================private static final Log logger = LogFactory.getLog(FilterChainProxy.class);// ~ Instance fields// ================================================================================================private final static String FILTER_APPLIED = FilterChainProxy.class.getName().concat(".APPLIED");/**存储过滤器链**/private List<SecurityFilterChain> filterChains;private FilterChainValidator filterChainValidator = new NullFilterChainValidator();private HttpFirewall firewall = new StrictHttpFirewall();// ~ Methods// ========================================================================================================public FilterChainProxy() {}public FilterChainProxy(SecurityFilterChain chain) {this(Arrays.asList(chain));}public FilterChainProxy(List<SecurityFilterChain> filterChains) {this.filterChains = filterChains;}@Overridepublic void afterPropertiesSet() {filterChainValidator.validate(this);}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;if (clearContext) {try {request.setAttribute(FILTER_APPLIED, Boolean.TRUE);doFilterInternal(request, response, chain);}finally {SecurityContextHolder.clearContext();request.removeAttribute(FILTER_APPLIED);}}else {doFilterInternal(request, response, chain);}}private void doFilterInternal(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {FirewalledRequest fwRequest = firewall.getFirewalledRequest((HttpServletRequest) request);HttpServletResponse fwResponse = firewall.getFirewalledResponse((HttpServletResponse) response);/** 获取过滤器 */List<Filter> filters = getFilters(fwRequest);if (filters == null || filters.size() == 0) {if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(fwRequest)+ (filters == null ? " has no matching filters": " has an empty filter list"));}fwRequest.reset();/** 挨个执行过滤器*/chain.doFilter(fwRequest, fwResponse);return;}VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);vfc.doFilter(fwRequest, fwResponse);}/*** Returns the first filter chain matching the supplied URL.** @param request the request to match* @return an ordered array of Filters defining the filter chain*/private List<Filter> getFilters(HttpServletRequest request) {for (SecurityFilterChain chain : filterChains) {if (chain.matches(request)) {return chain.getFilters();}}return null;}/*** Convenience method, mainly for testing.** @param url the URL* @return matching filter list*/public List<Filter> getFilters(String url) {return getFilters(firewall.getFirewalledRequest((new FilterInvocation(url, "GET").getRequest())));}/*** @return the list of {@code SecurityFilterChain}s which will be matched against and* applied to incoming requests.*/public List<SecurityFilterChain> getFilterChains() {return Collections.unmodifiableList(filterChains);}/*** Used (internally) to specify a validation strategy for the filters in each* configured chain.** @param filterChainValidator the validator instance which will be invoked on during* initialization to check the {@code FilterChainProxy} instance.*/public void setFilterChainValidator(FilterChainValidator filterChainValidator) {this.filterChainValidator = filterChainValidator;}/*** Sets the "firewall" implementation which will be used to validate and wrap (or* potentially reject) the incoming requests. The default implementation should be* satisfactory for most requirements.** @param firewall*/public void setFirewall(HttpFirewall firewall) {this.firewall = firewall;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append("FilterChainProxy[");sb.append("Filter Chains: ");sb.append(filterChains);sb.append("]");return sb.toString();}// ~ Inner Classes// ==================================================================================================/*** Internal {@code FilterChain} implementation that is used to pass a request through* the additional internal list of filters which match the request.*/private static class VirtualFilterChain implements FilterChain {private final FilterChain originalChain;private final List<Filter> additionalFilters;private final FirewalledRequest firewalledRequest;private final int size;private int currentPosition = 0;private VirtualFilterChain(FirewalledRequest firewalledRequest,FilterChain chain, List<Filter> additionalFilters) {this.originalChain = chain;this.additionalFilters = additionalFilters;this.size = additionalFilters.size();this.firewalledRequest = firewalledRequest;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {if (currentPosition == size) {if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)+ " reached end of additional filter chain; proceeding with original chain");}// Deactivate path stripping as we exit the security filter chainthis.firewalledRequest.reset();originalChain.doFilter(request, response);}else {currentPosition++;Filter nextFilter = additionalFilters.get(currentPosition - 1);if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)+ " at position " + currentPosition + " of " + size+ " in additional filter chain; firing Filter: '"+ nextFilter.getClass().getSimpleName() + "'");}nextFilter.doFilter(request, response, this);}}}public interface FilterChainValidator {void validate(FilterChainProxy filterChainProxy);}private static class NullFilterChainValidator implements FilterChainValidator {@Overridepublic void validate(FilterChainProxy filterChainProxy) {}}}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词