Spring security filter详解(5.1.6)

1.Spring security filter

1.1默认filter链,在程序启动时会打印出如下日志,该日志打印出了默认的filter链和顺序,其中WebAsyncManagerIntegrationFilter为第一个filter,FilterSecurityInterceptor为最后一个filter。

2019-11-19 10:26:54.340  INFO 17148 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : 
Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/oauth/token'], Ant [pattern='/oauth/token_key'], Ant [pattern='/oauth/check_token']]], 
 [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@58d4238e,
 org.springframework.security.web.context.SecurityContextPersistenceFilter@6c835217,
 org.springframework.security.web.header.HeaderWriterFilter@7d59e968,
 org.springframework.security.web.authentication.logout.LogoutFilter@6750e381,
 org.springframework.security.web.authentication.www.BasicAuthenticationFilter@78d73b1b,
 org.springframework.security.web.savedrequest.RequestCacheAwareFilter@51888019,
 org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@26da1ba2,
 org.springframework.security.web.authentication.AnonymousAuthenticationFilter@72a8361b, 
 org.springframework.security.web.session.SessionManagementFilter@4f3356c0, 
 org.springframework.security.web.access.ExceptionTranslationFilter@5a2ae1ab,
 org.springframework.security.web.access.intercept.FilterSecurityInterceptor@6486fe7b]

 1.2内置过滤器初始化

在 Spring Security 初始化核心过滤器时 HttpSecurity 会通过将 Spring Security 内置的一些过滤器以 FilterComparator 提供的规则进行比较按照比较结果进行排序注册。

FilterComparator 维护了一个顺序的注册表 filterToOrder 。

    FilterComparator() {
        FilterComparator.Step order = new FilterComparator.Step(100, 100);
        this.put(ChannelProcessingFilter.class, order.next());
        this.put(ConcurrentSessionFilter.class, order.next());
        this.put(WebAsyncManagerIntegrationFilter.class, order.next());
        this.put(SecurityContextPersistenceFilter.class, order.next());
        this.put(HeaderWriterFilter.class, order.next());
        this.put(CorsFilter.class, order.next());
        this.put(CsrfFilter.class, order.next());
        this.put(LogoutFilter.class, order.next());
        this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter", order.next());
        this.put(X509AuthenticationFilter.class, order.next());
        this.put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
        this.filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next());
        this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter", order.next());
        this.put(UsernamePasswordAuthenticationFilter.class, order.next());
        this.put(ConcurrentSessionFilter.class, order.next());
        this.filterToOrder.put("org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
        this.put(DefaultLoginPageGeneratingFilter.class, order.next());
        this.put(DefaultLogoutPageGeneratingFilter.class, order.next());
        this.put(ConcurrentSessionFilter.class, order.next());
        this.put(DigestAuthenticationFilter.class, order.next());
        this.filterToOrder.put("org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter", order.next());
        this.put(BasicAuthenticationFilter.class, order.next());
        this.put(RequestCacheAwareFilter.class, order.next());
        this.put(SecurityContextHolderAwareRequestFilter.class, order.next());
        this.put(JaasApiIntegrationFilter.class, order.next());
        this.put(RememberMeAuthenticationFilter.class, order.next());
        this.put(AnonymousAuthenticationFilter.class, order.next());
        this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter", order.next());
        this.put(SessionManagementFilter.class, order.next());
        this.put(ExceptionTranslationFilter.class, order.next());
        this.put(FilterSecurityInterceptor.class, order.next());
        this.put(SwitchUserFilter.class, order.next());
    }

通过以下方法获取序号

    private Integer getOrder(Class<?> clazz) {
        while(clazz != null) {
            Integer result = (Integer)this.filterToOrder.get(clazz.getName());
            if (result != null) {
                return result;
            }

            clazz = clazz.getSuperclass();
        }

        return null;
    }

序号越小优先级越高。上面的过滤器并非全部会被初始化。有的需要额外引入一些功能包,有的看 HttpSecurity 的配置情况。

 2.内置过滤器笔记

2.1ChannelProcessingFilter

ChannelProcessingFilter 通常是用来过滤哪些请求必须用 https 协议, 哪些请求必须用 http 协议, 哪些请求随便用哪个协议都行。它主要有两个属性:

ChannelDecisionManager 用来判断请求是否符合既定的协议规则。它维护了一个 ChannelProcessor 列表 这些ChannelProcessor 是具体用来执行 ANY_CHANNEL 策略 (任何通道都可以), REQUIRES_SECURE_CHANNEL 策略 (只能通过https 通道), REQUIRES_INSECURE_CHANNEL 策略 (只能通过 http 通道)。

FilterInvocationSecurityMetadataSource 用来存储 url 与 对应的ANY_CHANNEL、REQUIRES_SECURE_CHANNEL、REQUIRES_INSECURE_CHANNEL 的映射关系。

ChannelProcessingFilter 通过 HttpScurity#requiresChannel() 等相关方法引入其配置对象 ChannelSecurityConfigurer 来进行配置。

2.2ConcurrentSessionFilter

ConcurrentSessionFilter 主要用来判断session是否过期以及更新最新的访问时间。其流程为:

session 检测,如果不存在直接放行去执行下一个过滤器。存在则进行下一步。根据sessionid从SessionRegistry中获取SessionInformation,从SessionInformation中获取session是否过期;没有过期则更新SessionInformation中的访问日期;
如果过期,则执行doLogout()方法,这个方法会将session无效,并将 SecurityContext 中的Authentication中的权限置空,同时在SecurityContenxtHoloder中清除SecurityContext然后查看是否有跳转的 expiredUrl,如果有就跳转,没有就输出提示信息。
ConcurrentSessionFilter 通过SessionManagementConfigurer 来进行配置。
2.3WebAsyncManagerIntegrationFilter

WebAsyncManagerIntegrationFilter用于集成SecurityContext到Spring异步执行机制中的WebAsyncManager。用来处理异步请求的安全上下文。具体逻辑为:

从请求属性上获取所绑定的WebAsyncManager,如果尚未绑定,先做绑定。
从asyncManager 中获取 key 为 CALLABLE_INTERCEPTOR_KEY 的安全上下文多线程处理器 SecurityContextCallableProcessingInterceptor, 如果获取到的为 null,
新建一个 SecurityContextCallableProcessingInterceptor 并绑定 CALLABLE_INTERCEPTOR_KEY 注册到 asyncManager 中。
这里简单说一下 SecurityContextCallableProcessingInterceptor 。它实现了接口 CallableProcessingInterceptor,
当它被应用于一次异步执行时,beforeConcurrentHandling() 方法会在调用者线程执行,该方法会相应地从当前线程获取SecurityContext,然后被调用者线程中执行逻辑时,会使用这个 SecurityContext,从而实现安全上下文从调用者线程到被调用者线程的传输。

WebAsyncManagerIntegrationFilter 通过 WebSecurityConfigurerAdapter#getHttp()方法添加到 HttpSecurity 中成为 DefaultSecurityFilterChain 的一个链节。

2.4SecurityContextPersistenceFilter

SecurityContextPersistenceFilter 主要控制 SecurityContext 的在一次请求中的生命周期 。 请求来临时,创建SecurityContext 安全上下文信息,请求结束时清空 SecurityContextHolder。

SecurityContextPersistenceFilter 通过 HttpScurity#securityContext() 及相关方法引入其配置对象 SecurityContextConfigurer 来进行配置。
2.5HeaderWriterFilter

HeaderWriterFilter 用来给 http 响应添加一些 Header,比如 X-Frame-Options, X-XSS-Protection ,X-Content-Type-Options。

你可以通过 HttpScurity#headers() 来定制请求Header 。
2.6CorsFilter

跨域相关的过滤器。你可以通过 HttpSecurity#cors() 来定制。

2.7CsrfFilter

CsrfFilter 用于防止csrf攻击,前后端使用json交互需要注意的一个问题。你可以通过 HttpSecurity.csrf() 来开启或者关闭它。在你使用 jwt 等 token 技术时,是不需要这个的。

2.8LogoutFilter

LogoutFilter 很明显这是处理注销的过滤器。你可以通过 HttpSecurity.logout() 来定制注销逻辑,非常有用。

2.9OAuth2AuthorizationRequestRedirectFilter

和上面的有所不同,这个需要依赖 spring-scurity-oauth2 相关的模块。

2.10X509AuthenticationFilter

X509 认证过滤器。你可以通过 HttpSecurity#X509() 来启用和配置相关功能。

2.11AbstractPreAuthenticatedProcessingFilter

AbstractPreAuthenticatedProcessingFilter 处理处理经过预先认证的身份验证请求的过滤器的基类,其中认证主体已经由外部系统进行了身份验证。 目的只是从传入请求中提取主体上的必要信息,而不是对它们进行身份验证。

你可以继承该类进行具体实现并通过 HttpSecurity#addFilter 方法来添加个性化的AbstractPreAuthenticatedProcessingFilter 。
2.12CasAuthenticationFilter

CAS 单点登录认证过滤器 。依赖 Spring Security CAS 模块

2.13OAuth2LoginAuthenticationFilter

这个需要依赖 spring-scurity-oauth2 相关的模块。OAuth2 登录认证过滤器。处理通过 OAuth2 进行认证登录的逻辑。

2.14UsernamePasswordAuthenticationFilter

处理用户以及密码认证的核心过滤器。认证请求提交的username和 password,被封装成token进行一系列的认证,便是主要通过这个过滤器完成的,在表单认证的方法中,这是最最关键的过滤器。你可以通过 HttpSecurity#formLogin() 及相关方法引入其配置对象 FormLoginConfigurer 来进行配置。

2.15ConcurrentSessionFilter

看上面2.2, 该过滤器可能会被多次执行。

2.16OpenIDAuthenticationFilter

基于OpenID 认证协议的认证过滤器。 你需要在依赖中依赖额外的相关模块才能启用它。

2.17DefaultLoginPageGeneratingFilter

生成默认的登录页。默认 /login 。

2.18 DefaultLogoutPageGeneratingFilter

生成默认的退出页。 默认 /logout 。

2.19ConcurrentSessionFilter

看上面2.2, 该过滤器可能会被多次执行。

2.20DigestAuthenticationFilter

Digest身份验证是 Web 应用程序中流行的可选的身份验证机制 。DigestAuthenticationFilter 能够处理 HTTP 头中显示的摘要式身份验证凭据。你可以通过 HttpSecurity#addFilter() 来启用和配置相关功能。

2.21BearerTokenAuthenticationFilter

2.22BasicAuthenticationFilter

和Digest身份验证一样都是Web 应用程序中流行的可选的身份验证机制 。 BasicAuthenticationFilter 负责处理 HTTP 头中显示的基本身份验证凭据。这个 Spring Security 的 Spring Boot 自动配置默认是启用的 。

BasicAuthenticationFilter 通过 HttpSecurity#httpBasic() 及相关方法引入其配置对象 HttpBasicConfigurer 来进行配置。
2.23RequestCacheAwareFilter

用于用户认证成功后,重新恢复因为登录被打断的请求。当匿名访问一个需要授权的资源时。会跳转到认证处理逻辑,此时请求被缓存。在认证逻辑处理完毕后,从缓存中获取最开始的资源请求进行再次请求。RequestCacheAwareFilter 通过 HttpScurity#requestCache() 及相关方法引入其配置对象 RequestCacheConfigurer 来进行配置。
2.24 SecurityContextHolderAwareRequestFilter

用来 实现j2ee中 Servlet Api 一些接口方法, 比如 getRemoteUser 方法、isUserInRole 方法,在使用 Spring Security 时其实就是通过这个过滤器来实现的。SecurityContextHolderAwareRequestFilter 通过 HttpSecurity.servletApi() 及相关方法引入其配置对象 ServletApiConfigurer 来进行配置。
2.25JaasApiIntegrationFilter

适用于JAAS (Java 认证授权服务)。 如果 SecurityContextHolder 中拥有的 Authentication 是一个 JaasAuthenticationToken,那么该 JaasApiIntegrationFilter 将使用包含在 JaasAuthenticationToken 中的 Subject 继续执行 FilterChain。
2.26RememberMeAuthenticationFilter

处理 记住我 功能的过滤器。RememberMeAuthenticationFilter 通过 HttpSecurity.rememberMe() 及相关方法引入其配置对象 RememberMeConfigurer 来进行配置。

2.27AnonymousAuthenticationFilter

匿名认证过滤器。对于 Spring Security 来说,所有对资源的访问都是有 Authentication 的。对于无需登录(UsernamePasswordAuthenticationFilter )直接可以访问的资源,会授予其匿名用户身份。AnonymousAuthenticationFilter 通过 HttpSecurity.anonymous() 及相关方法引入其配置对象 AnonymousConfigurer 来进行配置。

2.28OAuth2AuthorizationCodeGrantFilter


2.29SessionManagementFilter

Session 管理器过滤器,内部维护了一个 SessionAuthenticationStrategy 用于管理 Session 。SessionManagementFilter 通过 HttpScurity#sessionManagement() 及相关方法引入其配置对象 SessionManagementConfigurer 来进行配置。

2.30ExceptionTranslationFilter

主要来传输异常事件

2.31FilterSecurityInterceptor

这个过滤器决定了访问特定路径应该具备的权限,访问的用户的角色,权限是什么?访问的路径需要什么样的角色和权限?这些判断和处理都是由该类进行的。如果你要实现动态权限控制就必须研究该类 。

2.32SwitchUserFilter

SwitchUserFilter 是用来做账户切换的。默认的切换账号的url/login/impersonate,默认注销切换账号的url/logout/impersonate,默认的账号参数为username 。你可以通过此类实现自定义的账户切换。

总结:这里总共有32个过滤器,除去ConcurrentSessionFilter重复的三个,那么有30个。,有一些默认已经启用。有一些需要引入特定的包并且对 HttpSecurity 进行配置才会生效 。

在默认情况下进行调试,我们看一下我们的默认的过滤器有哪些

猜你喜欢

转载自blog.csdn.net/qq_36850813/article/details/103137328