Spring Security源码

文章讲述了WebSecurityConfigurerAdapter的废弃以及官方推荐的HttpSecurity和SecurityBuilder接口的使用。重点介绍了SecurityBuilder的构建过程,以及如何通过HttpSecurity控制过滤器链和配置。同时提到了debug模式的启用和虚拟过滤器的应用.

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述
WebSecurityConfigurerAdapter已废弃,官方推荐使用HttpSecurity 或WebSecurity。
在这里插入图片描述
在这里插入图片描述
都继承了SecurityBuilder

public interface SecurityBuilder<O> {

	O build() throws Exception;

}

亮点:通过这种方式很容易知道知道自己构建的Object

HttpSecurity

public interface SecurityFilterChain {
	/**
	** 判断请求是否能够匹配上这些过滤器
	**/
	boolean matches(HttpServletRequest request);
	/**
	** 过滤器列表
	**/
	List<Filter> getFilters();
}

AbstractSecurityBuilder.class 用途:确保仅构建1次,调用子类的doBuild方法去构建对象

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {

	private AtomicBoolean building = new AtomicBoolean();

	private O object;
	/**
	* 防止重复构建
	**/
	@Override
	public final O build() throws Exception {
		if (this.building.compareAndSet(false, true)) {
			this.object = doBuild();
			return this.object;
		}
		throw new AlreadyBuiltException("This object has already been built");
	}

	/**
	 * Gets the object that was built. If it has not been built yet an Exception is
	 * thrown.
	 * @return the Object that was built
	 */
	public final O getObject() {
		if (!this.building.get()) {
			throw new IllegalStateException("This object has not been built");
		}
		return this.object;
	}

	/**
	 * 给子类自己实现
	 */
	protected abstract O doBuild() throws Exception;

}

AbstractConfiguredSecurityBuilder.class
扩展点:beforeInit、beforeConfigure

	@Override
	protected final O doBuild() throws Exception {
		synchronized (this.configurers) {
			this.buildState = BuildState.INITIALIZING;
			beforeInit();
			init();
			this.buildState = BuildState.CONFIGURING;
			beforeConfigure();
			configure();
			this.buildState = BuildState.BUILDING;
			O result = performBuild();
			this.buildState = BuildState.BUILT;
			return result;
		}
	}
	protected void beforeInit() throws Exception {
	}
	protected void beforeConfigure() throws Exception {
	}
	/**
	* 重要方法
	**/
	protected abstract O performBuild() throws Exception;
	
	@SuppressWarnings("unchecked")
	private void init() throws Exception {
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.init((B) this);
		}
		for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
			configurer.init((B) this);
		}
	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ee30dc929c5d4198a7720973fd04a77f.png

AbstractConfiguredSecurityBuilder.class

	private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();
	// 初始化添加的过滤器
	private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>();

	private final Map<Class<?>, Object> sharedObjects = new HashMap<>();
	private final boolean allowConfigurersOfSameType;
	// 构建状态
	private BuildState buildState = BuildState.UNBUILT;
	// 后置处理
	private ObjectPostProcessor<Object> objectPostProcessor;
	private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
		Assert.notNull(configurer, "configurer cannot be null");
		Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
				.getClass();
		synchronized (this.configurers) {
			if (this.buildState.isConfigured()) {
				throw new IllegalStateException("Cannot apply " + configurer + " to already built object");
			}
			List<SecurityConfigurer<O, B>> configs = null;
			if (this.allowConfigurersOfSameType) {
				configs = this.configurers.get(clazz);
			}
			configs = (configs != null) ? configs : new ArrayList<>(1);
			configs.add(configurer);
			this.configurers.put(clazz, configs);
			// 如果正在初始化往里面添加configurer,会在doBuild方法中使用
			if (this.buildState.isInitializing()) {
				this.configurersAddedInInitializing.add(configurer);
			}
		}
	}

HttpSecurity.class

	@Override
	protected void beforeConfigure() throws Exception {
		if (this.authenticationManager != null) {
			setSharedObject(AuthenticationManager.class, this.authenticationManager);
		}
		else {
			setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
		}
	}
private void configure() throws Exception {
	Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
	for (SecurityConfigurer<O, B> configurer : configurers) {
		configurer.configure((B) this);
	}
}

performBuild方法
在这里插入图片描述
WebSecurity.java 本质上一个FilterChainProxy

	@Override
	protected Filter performBuild() throws Exception {
		......
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		......
		Filter result = filterChainProxy;
		if (this.debugEnabled) {
			.....
			result = new DebugFilter(filterChainProxy);
		}
		return result;
	}

可以通过@EnableWebSecurity(debug = true)开启debug模式
new DebugFilter(filterChainProxy)对filterChainProxy进行装饰

	public FilterChainProxy(List<SecurityFilterChain> filterChains) {
		this.filterChains = filterChains;
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
			......
			doFilterInternal(request, response, chain);
			......
	}

	private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// HttpFirewall实例用于验证传入请求并创建包装请求,该请求提供一致的路径值以进行匹配。
		FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request);
		// 获取到匹配的filter
		List<Filter> filters = getFilters(firewallRequest);
		......
		// 虚拟过滤器,挨个应用filters
		VirtualFilterChain virtualFilterChain = new VirtualFilterChain(firewallRequest, chain, filters);
		virtualFilterChain.doFilter(firewallRequest, firewallResponse);
	}

	// 获取匹配的filter
	private List<Filter> getFilters(HttpServletRequest request) {
		int count = 0;
		for (SecurityFilterChain chain : this.filterChains) {
			......
			if (chain.matches(request)) {
				return chain.getFilters();
			}
		}
		return null;
	}

// 虚拟过滤器,挨个应用filters
@Override
		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;
			}
			this.currentPosition++;
			Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
			if (logger.isTraceEnabled()) {
				logger.trace(LogMessage.format("Invoking %s (%d/%d)", nextFilter.getClass().getSimpleName(),
						this.currentPosition, this.size));
			}
			nextFilter.doFilter(request, response, this);
		}

HttpSecurity.java

	@SuppressWarnings("unchecked")
	@Override
	protected DefaultSecurityFilterChain performBuild() {
	......
	// 确保其中一个为null
		boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
		return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
	}

在这里插入图片描述
在这里插入图片描述
饿汉模式创建的一个任意请求匹配器,matches返回的都是true
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值