时间:2023-01-10 11:52:48 | 栏目:JAVA代码 | 点击:次
Spring Security 采用 IoC 和 AOP思想,基于 Servlet 过滤器实现的安全框架、为 Web 请求和方法调用提供身份确认和授权处理,还提供与其他库的集成以简化其使用,避免了代码耦合,减少了大量重复代码工作。
在之前 web.xml中,我们是这样写的。
<!--SpringSecurity核心过滤器链--> <!--springSecurityFilterChain名词不能修改--> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在 Spring Boot项目之后,我们引入 Spring Security依赖,什么也没做,启动项目 Spring Security 就会生效,访问请求就进行了拦截。
Spring Boot 对于 Spring Security 提供了自动化配置方案,可以使用更少的配置来使用 Spring Security。
那么这个过滤器链是怎么加载和实现拦截的呢?
当 Spring Boot 项目启动后,SecurityFilterAutoConfiguration类会加载 DelegatingFilterProxyRegistrationBean注册过滤器,名字为 springSecurityFilterChain。
注意:
springSecurityFilterChain名字是固定写死的。
DelegatingFilterProxyRegistrationBean 注册成功后,该过滤器就被加载了到了注册器中。
注册器注册了所有的过滤器后,会为每个过滤器生成 DelegatingFilterProxy代理对象并注册到 IoC中 。
我们访问项目,就会进入 DelegatingFilterProxy类的 doFilter方法。
DelegatingFilterProxy类
本质也是一个 Filter,其间接实现了 Filter接口,但是在 doFilter中其实调用的从 Spring 容器中获取到的代理 Filter的实现类。
返回的 FilterChainProxy对象。
由此可知,DelegatingFilterProxy类通过 springSecurityFilterChain这个名称,得到了一个 FilterChainProxy过滤器,最终执行的是这个过滤器的 doFilter方法。
1)验证 springSecurityFilterChain名词不能修改
查看 initDelegate方法。
FilterChainProxy类
本质也是一个 Filter,所以查看 doFilter方法。留意该类里面的属性。
public class FilterChainProxy extends GenericFilterBean { private static final Log logger = LogFactory.getLog(FilterChainProxy.class); private static final String FILTER_APPLIED = FilterChainProxy.class.getName().concat(".APPLIED"); // 过滤器链 private List<SecurityFilterChain> filterChains; private FilterChainProxy.FilterChainValidator filterChainValidator; private HttpFirewall firewall;
惊不惊喜?15个过滤器都在这里了!
原来这些过滤器都被封装进 SecurityFilterChain对象中。
SecurityFilterChain类
是个接口,实现类也只有一个 DefaultSecurityFilterChain类
。
DefaultSecurityFilterChain类的构造方法,初始化了 List filters,是通过传参放进去的。
过滤器链参数是什么时候传入的?
创建 Spring Security 过滤器链是交给 Spring boot 自动配置,由 SpringBootWebSecurityConfiguration类
创建注入。
查看 WebSecurityConfigurerAdapter类。
然后会注入 HttpSecurity对象,HttpSecurity可以理解为 Spring Security 的 http核心配置,存放 Spring Security 中的过滤器链、请求匹配路径等相关认证授权的重要方法。
然后开始创建 Spring Security 过滤器链了,是交给 Spring Boot自动配置,一共有 15个过滤器。
使用 OrderedFilter进行代理,并设置了order属性。
添加完成后,将这些过滤器再封装为 DefaultSecurityFilterChain对象。
最后通过 WebSecurityConfiguration配置加载 springSecurityFilterChain,WebSecurityConfiguration中维护了securityFilterChains属性,会存放过滤器链中所有的过滤器。
总结:
Spring boot 通过 DelegatingFilterProxyRegistrationBean注册过滤器,名字为 springSecurityFilterChain,并生成 DelegatingFilterProxy代理对象并注册到 IoC中。最终真正调用 FilterChainProxy过滤器的 doFilter 获取到 Spring Security 过滤器链。
Spring Security的过滤器链在底层是封装在 SecurityFilterChain接口中的。
首先进入的是 OncePerRequestFilter 过滤器。
OncePerRequestFilter是为了确保一次请求中只通过一次filter,而不需要重复的执行。
会进入 DelegatingFilterProxy代理对象中 invokeDelegate方法,实际真正执行的是 FilterChainProxy过滤器的 doFilter 方法。
查看 FilterChainProxy过滤器中的 doFilterInternal方法。
然后首先进入FilterChainProxy中的 doFilterInternal方法。
doFilterInternal方法中会调用 getFilters方法,会从过滤器链中拿出所有的拦截器。
然后创建一个 VirtualFilterChain对象,一个虚拟的过滤器链,并执行其中的 doFilter 方法。使用过滤器对当前请求进行层层过滤。
最后进入到 FilterSecurityInterceptor过滤器中,该过滤器是过滤器链的最后一个过滤器,invoke方法中。
先调用父类的 beforeInvocation方法,之后调用 filterChain的 doFilter方法,之后调用父类的 finallyInvocation和afterInvocation方法。
在 beforeInvocation方法中,如果当前的请求没有通过认证,会抛出 Access is denied异常,这个异常会被ExceptionTranslationFilter过滤器处理。如果抛出的异常是 AuthenticationException,则执行方法sendStartAuthentication方法。
最终调用 EntryPoint的 commence方法,发布异常。
1、WebAsyncManagerIntegrationFilter
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
其主要用于集成 SecurityContext到 Spring异步执行机制中的 WebAsyncManager。
2、SecurityContextPersistenceFilter
org.springframework.security.web.context.SecurityContextPersistenceFilter
其主要是使用 SecurityContextRepository在 session中保存或更新一个SecurityContext,并将 SecurityContext给以后的过滤器使用,来为后续 filter建立所需的上下文。SecurityContext
中存储了当前用户的认证以及权限信息。
3、HeaderWriterFilter
org.springframework.security.web.header.HeaderWriterFilter
其主要是向请求的 Header中添加相应的信息,可在 http标签内部使用 security:headers来控制。
4、CsrfFilter
org.springframework.security.web.csrf.CsrfFilter
csrf又称跨域请求伪造
,SpringSecurity会对所有 post请求验证是否包含系统生成的 csrf的 token信息,
如果不包含,则报错。起到防止csrf攻击的效果。
5、LogoutFilter
org.springframework.security.web.authentication.logout.LogoutFilter
其主要用于实现用户退出,清除认证信息。默认匹配 URL为 /logout的请求。
6、UsernamePasswordAuthenticationFilter
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
其主要用于认证操作,默认匹配URL为 /login且必须为POST请求。
7、DefaultLoginPageGeneratingFilter
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
如果没有在配置文件中指定认证页面,则由该过滤器生成一个默认认证页面。
8、DefaultLogoutPageGeneratingFilter
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter
由此过滤器可以生产一个默认的退出登录页面
9、BasicAuthenticationFilter
org.springframework.security.web.authentication.www.BasicAuthenticationFilter
此过滤器会自动解析 HTTP请求中头部名字为 Authentication,且以 Basic开头的头信息。
10、RequestCacheAwareFilter
org.springframework.security.web.savedrequest.RequestCacheAwareFilter
通过HttpSessionRequestCache内部维护了一个 RequestCache,用于缓存 HttpServletRequest。
11、SecurityContextHolderAwareRequestFilter
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
针对 ServletRequest进行了一次包装,使得 request具有更加丰富的 API。
12、AnonymousAuthenticationFilter
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
当 SecurityContextHolder中认证信息为空,则会创建一个匿名用户
存入到 SecurityContextHolder中。
Spring Security为了兼容未登录的访问,也走了一套认证流程,只不过是一个匿名的身份。
13、SessionManagementFilter
org.springframework.security.web.session.SessionManagementFilter
其主要用于限制同一用户开启多个会话的数量。
14、ExceptionTranslationFilter
org.springframework.security.web.access.ExceptionTranslationFilter
异常转换过滤器位于整个 springSecurityFilterChain的后方,用来转换整个链路中出现的异常。ExceptionTranslationFilter过滤器会拦截处理 AccessDeniedException和 AuthenticationException并添加到HTTP响应中。
15、FilterSecurityInterceptor
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
获取所配置资源访问的授权信息,根据 SecurityContextHolder中存储的用户信息来决定其是否有权限。