Spring Security Filter在HTTP请求到达你的Controller之前,过滤每一个传入的HTTP请求
首先,过滤器需要从请求中提取一个用户名/密码。它可以通过一个基本的HTTP头,或者表单字段,或者cookie等等。
然后,过滤器需要对用户名/密码组合进行验证比如数据库。
在验证成功后,过滤器需要检查用户是否被授权访问请求的URI。
如果请求通过了所有这些检查,那么过滤器就可以让请求通过你的DispatcherServlet后重定向到@Controllers或者@RestController。
要使Spring Security生效,从可行性上来说,我们需要有一个Spring Security的Filter能够被Servlet容器(比如Tomcat、Undertow等)感知到,这个Filter便是DelegatingFilterProxy,该Filter并不受Spring IoC容器的管理,也不是Spring Security引入的,而是Spring Framework中的一个通用的Filter。在Servlet容器眼中,DelegatingFilterProxy只是一个Filter而已,跟其他的Servlet Filter没什么却别。
虽然DelegatingFilterProxy本身不在IoC容器中,它却能够访问到IoC容器中的其他对象(通过WebApplicationContextUtils.getWebApplicationContext可以获取到IoC容器,进而操作容器中的Bean),这些对象才是真正完成Spring Security逻辑的对象。这些对象中的部分对象本身也实现了javax.servlet.Filter接口,但是他们并不能被Servlet容器感知到,比如UsernamePasswordAuthenticationFilter。
过滤器链通过这个过滤器示例,可以了解到通过过滤器完成认证和授权的基本过程。
在SpringSecurity中,这一过程不是通过一个过滤器来完成的,而是一系列的过滤器,也就是一个过滤器链,认证有认证的过滤器,授权有授权的过滤器,除此之外还有更多的,不同功能的过滤器
这种过滤器链的好处:
每个过滤器的职责单一
链式处理是一种比较好的方式,由简单的逻辑构成复杂的逻辑
当一个项目启动的时候,其Spring Security的日志输出:
2021-09-18 14:10:50.935 INFO 8265 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@56da7487, org.springframework.security.web.context.SecurityContextPersistenceFilter@6f94a5a5, org.springframework.security.web.header.HeaderWriterFilter@7ceb4478, org.springframework.security.web.authentication.logout.LogoutFilter@7cbeac65, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@a451491, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@a92be4f, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@10f7c76, org.springframework.security.web.session.SessionManagementFilter@25ad4f71, org.springframework.security.web.access.ExceptionTranslationFilter@77bbadc, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@2b680207]这就是Spring Security的过滤器链
重新访问/api/greeing这个路径,我们来看看日志:
2021-09-18 14:10:54.545 DEBUG 8004 --- [nio-8080-exec-1] FilterSecurityInterceptor : Failed to authorize filter invocation [GET /api/greeting] with attributes [authenticated] 2021-09-18 14:10:54.545 DEBUG 8004 --- [nio-8080-exec-1] HttpSessionRequestCache : Saved request :8080/api/greeting to session 2021-09-18 14:10:54.545 DEBUG 8004 --- [nio-8080-exec-1] DefaultRedirectStrategy : Redirecting to :8080/login认证失败,重定向到了login
登录之后:
2021-09-18 14:11:03.247 DEBUG 8004 --- [nio-8080-exec-6] DaoAuthenticationProvider : Authenticated user ... ... 2021-09-18 14:11:03.247 DEBUG 8004 --- [nio-8080-exec-6] DefaultRedirectStrategy : Redirecting to :8080/api/greeting ... ... 2021-09-18 14:11:03.247 DEBUG 8004 --- [nio-8080-exec-9] FilterSecurityInterceptor : Authorized filter invocation [GET /api/greeting] with attributes [authenticated] 2021-09-18 14:11:03.247 DEBUG 8004 --- [nio-8080-exec-9] FilterChainProxy : Secured GET /api/greeting 常见的内建过滤器链SpringSecurity过滤器很多,并且还可以自己添加过滤器,如何添加过滤器我们之后在分析认证流程源码的时候会介绍。
不需要将每个SpringSecurity过滤器都搞明白,只需要知道一些常见的过滤器的作用就行了
org.springframework.security.web.authentication.
此过滤器会自动解析HTTP请求中头部名字为Authentication,且以Basic开头的头信息。
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
认证操作全靠这个过滤器,默认匹配URL为/login且必须为POST请求。之后我们自定义认证流程其实也是通过重写这个过滤器实现。
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
当SecurityContextHolder中认证信息为空,则会创建一个匿名用户存入到SecurityContextHolder中。SecurityContextHolder是什么在下一章解释
spring security为了兼容未登录的访问,也走了一套认证流程,只不过是一个匿名的身份。
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
如果没有在配置文件中指定认证页面,则由该过滤器生成一个默认认证页面。
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter
由此过滤器可以生产一个默认的退出登录页面
自定义Filter