The HttpSecurity class in Spring Security
在项目中实际使用 Spring Security 时,我们的大部分工作其实都是配置 HttpSecurity。要么通过 spring 的 http xml element 来配置,要么通过配置类里的 HttpSecurity class 来配置,所以在理解了 DelegatingFilterProxy,FilterChainProxy,SecurityFilterChain 之间的关系之后就很有必要了解一下 HttpSecurity 类了。
HttpSecurity 这个类的名称与它的实际功用相差甚远,其实把它称为 HttpSecurityFilterChainBuiler 应该更合适,因为它的作用就是利用构造器模式构造出 SecurityFilterChain 的一个实例供 FilterChainProxy 使用。这点从它的类签名就能看出来。
如果有多个 SecurityFilterChain 被配置、构造出来,它们的顺序可以通过注解 @Order 来设定。没有@Order 注解的优先级最低。同一 order 层级的,就可以通过 SecurityFilterChain 中的 RequestMatcher 来决定了该 chain 是否与 http request 匹配了。我们应该尽量把特殊的匹配放在前面,通用的放在后面。
1) 体会下 HttpSecurity 源码的定义部分:
2) 用 xml 配置 http security:
虽然现在基于 Spring 的开发都是基于注解的了,但是如果遇到遗留系统里通过 http 元素来定义 HttpSecurity,那么俯视一下下面的 schema 应该也能大致了然了。。。
3) fitlers 的顺序定义:
4) HttpSecurity build filter 的套路
看看与 authentication 相关的两个 fitler 的构建。
1)从两个 filter 看规律
Filter 都是根据 Configurer 构建出来的。我们以 BasicAuthenticationFilter 和 UsernamePasswordAuthenticationFilter 的 Configurer 举例。
FormLoginConfigurer 比较“特殊”,它定义了两个 filter。一个是 UsernamePasswordAuthenticationFilter, 一个是 DefaultLoginPageGeneratingFilter,后者提供了一个让用户输入 credential 页面的 filter。
HttpBasicConfigurer 则定义了 BasicAuthenticationFilter。
public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
return getOrApply(new FormLoginConfigurer<>());
}
public HttpBasicConfigurer<HttpSecurity> httpBasic() throws Exception {
return getOrApply(new HttpBasicConfigurer<>());
}
FormLoginConfigurer 是 AbstractAuthenticationFilterConfigurer 的子类, HttpBasicConfigurer 是 AbstractHttpConfigurer。这是因为 basic 的认证方式比起 form 形式的认证要简单得多。
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter>
extends AbstractHttpConfigurer<T, B> {
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends AbstractHttpConfigurer<HttpBasicConfigurer<B>, B> {
负责根据这些 configuer 构造出对象来的类是 AbstractConfiguredSecurityBuilder。
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>> extends AbstractSecurityBuilder<O> {
2) 没有被使用的 AuthenticationFilter
很奇怪在 Spring Security 的源码里没有看到 AuthenticationFilter 被使用。估计这是要让程序员通过提供自定义的 authenticationConverter 和 authenticationManagerResolver 来使用吧。
对比三个与 authentication 相关的 fitler 体会下。
BasicAuthenticationFilter
UsernamePasswordAuthenticationFitler
AuthenticationFilter
References:
[1]: https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#jc-httpsecurity
[2]: https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#_multiple_httpsecurity
[3]: https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#jc-custom-dsls
[4]: https://www.baeldung.com/spring-onceperrequestfilter