spring security 流程分析(1)

Filter

spring security 是借助于 Filter 过滤器机制来实现的并在过程中结合了spring的机制 那么就从DelegatingFilterProxy开始分析spring security的整体执行流程

1. DelegatingFilterProxy

这个类作为过滤器添加到tomcat的过滤器链中在执行过程会按照顺序执行到这个类

public class DelegatingFilterProxy extends GenericFilterBean {
	...
	@Nullable
	private volatile Filter delegate;// 这个类做为一个连接点
	...
}

参看DelegatingFilterProxy的doFilter方法用以设置delegate

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
	//懒加载单例模式 防止多个FilterChainProxy实例
	Filter delegateToUse = this.delegate;
	if (delegateToUse == null) {
		synchronized (this.delegateMonitor) {
			delegateToUse = this.delegate;
			if (delegateToUse == null) {
				WebApplicationContext wac = findWebApplicationContext();
				if (wac == null) {
					throw new IllegalStateException("No WebApplicationContext found: " +
							"no ContextLoaderListener or DispatcherServlet registered?");
				}
				//通过这个方法获取到FilterChainProxy实例对象(内部通过WebApplicationContext的getBean方法获取实例对象 通过targetName获取)
				delegateToUse = initDelegate(wac);
			}
			this.delegate = delegateToUse;
		}
	}
	//此方法是调用FilterChainProxy的doFilter方法
	invokeDelegate(delegateToUse, request, response, filterChain);
}

protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
	delegate.doFilter(request, response, filterChain);
}

2.FilterChainProxy

2.1 FilterChainProxy实例化过程

//this.securityFilterChains 成员填充
@Autowired(required = false)
void setFilterChains(List<SecurityFilterChain> securityFilterChains) {
	this.securityFilterChains = securityFilterChains;
}

@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
	...
	for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
		this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
		for (Filter filter : securityFilterChain.getFilters()) {
			if (filter instanceof FilterSecurityInterceptor) {
				this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
				break;
			}
		}
	}
	...
	return this.webSecurity.build();
}
	|
	V this.webSecurity.build() 创建FilterChianProxy
protected Filter performBuild() throws Exception {
	//去掉部分代码
	...
	//过滤器链列表
	List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
	...
	for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
		SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
		securityFilterChains.add(securityFilterChain);
		...
	}
	...
	//初始化过滤器代理的过滤器链用以在执行流程中执行
	FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
	filterChainProxy.afterPropertiesSet();
	Filter result = filterChainProxy;
	...
	this.postBuildAction.run();
	return result;
}

2.2 Spring Security 过滤器链

在这里插入图片描述

2.3 FilterChainProxy执行过程

FilterChainProxy 作为spring security的一个重要执行中转类会从spring ioc 中获取到所有的 spring security的过滤器并添加到内部filters成员中

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
	boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
	if (!clearContext) {
		doFilterInternal(request, response, chain);
		return;
	}
	try {
		request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
		doFilterInternal(request, response, chain);
	}catch (RequestRejectedException ex) {
		this.requestRejectedHandler.handle((HttpServletRequest) request, (HttpServletResponse) response, ex);
	}
	finally {
		SecurityContextHolder.clearContext();
		request.removeAttribute(FILTER_APPLIED);
	}
}
				 |
				 V
private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
	FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request);
	HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse) response);
	//获取 securityFilterChains 列表中的所有过滤器
	List<Filter> filters = getFilters(firewallRequest);
	//如果过滤器链列表为空或者没有过滤器则调用会调用ApplicationFilterChain.doFilter方法
	if (filters == null || filters.size() == 0) {
		firewallRequest.reset();
		chain.doFilter(firewallRequest, firewallResponse);
		return;
	}
	...
	//虚拟过滤器链 - 此处是spring security过滤器
	VirtualFilterChain virtualFilterChain = new VirtualFilterChain(firewallRequest, chain, filters);
	virtualFilterChain.doFilter(firewallRequest, firewallResponse);
}

3. VirtualFilterChain

VirtualFilterChain 类构造方法

private VirtualFilterChain(FirewalledRequest firewalledRequest, FilterChain chain,
				List<Filter> additionalFilters) {
	this.originalChain = chain; //ApplicationFilterChain
	this.additionalFilters = additionalFilters; //spring security过滤器列表
	this.size = additionalFilters.size();
	this.firewalledRequest = firewalledRequest;
}

VirtualFilterChina 类doFilter方法

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
	if (this.currentPosition == this.size) {
		if (logger.isDebugEnabled()) {
			logger.debug(LogMessage.of(() -> "Secured " + requestLine(this.firewalledRequest)));
		}
		// Deactivate path stripping as we exit the security filter chain
		this.firewalledRequest.reset();
		this.originalChain.doFilter(request, response);
		return;
	}
	//currentPosition全局变量是过滤器列表的偏移每执行一次当前类的doFilter方法都会+1
	this.currentPosition++;
	Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
	//调用过滤器链中过滤器 过滤器链列表在上图2.2
	//传入当前this对象 用以下一个过滤器调用doFilter方法并回到此处
	nextFilter.doFilter(request, response, this);
}

至此一个请求的处理流程从Tomcat的Filter到spring security的过滤器链流程分析完毕 下一章分析spring security的表单登陆请求处理过程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值