Spring Security 整体结构概览

Spring Security 概览

Spring Security的功能可以概括为两部分,即认证和授权。

认证就是一个用户使用令牌(最常见的是账号和密码)登陆,服务器验证这个用户的令牌是否有效。

授权则是认证之后,系统根据这个用户的信息判断他拥有哪些权限,能访问哪种资源,能对资源进何种操作,并向他授予相关的权限,对没有权限访问的用户进行阻止。

这里说的Spring Security是基于Servlet容器的。

从Filter说起

Spring Security的Servlet支持是基于Servlet的Filter的。Filter可以对请求进行处理,但Filter一般会将处理好的请求交给FilterChain中的下一个Filter,即一个个Filter按照相应的顺序组合起来形成了一个Filter链,从而达到对请求进行过滤/提前处理的效果。

Spring Security 整体结构概览_第1张图片

当请求到达时,Servlet容器会初始化一个FilterChain,并将请求传递到里面进行处理:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // do something before the rest of the application
    chain.doFilter(request, response); // invoke the rest of the application
    // do something after the rest of the application
}

经过一个个Filter处理后请求才到达Servlet处理并响应,由此可见,Filter在FilterChain中组织的顺序非常重要。

DelegatingFilterProxy

因为Servlet容器跟Spring的IoC容器是两种不同的容器,Servlet容器无法获知Spring容器中各种Bean(用户自定义Filter)的信息,也无法直接使用这些Bean(Filter),所以需要在两者间建立桥梁,使得我们定义的Bean(Filter)能够被Servlet容器使用。

Spring提供了一种叫DelegatingFilterProxy的Filter实现。

Spring Security 整体结构概览_第2张图片

它像普通的Filter一样被插入到FilterChain中,它的功能是将请求委托给Spring容器里的Bean Filter来处理,从而建立起Servlet容器和Spring容器之间的桥梁。

例如图中DelegatingFilterProxy会在Spring容器中寻找Bean Filter0,并将ServletRequestServletResponse传递过去:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // Lazily get Filter that was registered as a Spring Bean
    // For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
    Filter delegate = getFilterBean(someBeanName);
    // delegate work to the Spring Bean
    delegate.doFilter(request, response);
}

DelegatingFilterProxy的另一个好处是它可以延迟加载Bean Filter实例,因为FilterChain会在Servlet容器启动前初始化,这样可以提升Servlet容器启动的性能。

FilterChainProxy

上面提到DelegatingFilterProxy会将请求委托给Bean Filter,而其实这里的Bean Filter也不会直接处理请求,会将请求进一步转发,这个Bean Filter即是FilterChainProxy

FilterChainProxy是Spring Security提供的特殊Filter,它会将请求委托到另一种FilterChain中,即Spring的FilterChain:SecurityFilterChain

Spring Security 整体结构概览_第3张图片

我们可以很自然地想到,SecurityFilterChain中便是Spring的Bean Filter了,即SecurityFilter

Spring Security 整体结构概览_第4张图片

这里的SecurityFilter就是普通的Bean,他们可以识别自己能处理的请求并对请求处理,否则将请求传给链中的下一个Filter,例如最常见的UsernamePasswordAuthenticationFilter可以识别处理基于表单的登陆请求。

值得注意的是,SecurityFilterChain可以有多条,可以根据不同的请求来判断请求应该被传递到哪个SecurityFilterChain中:

比如符合/api/**匹配模式的URL应该被传递到最上面的SecurityFilterChain中,这个请求一旦匹配到了某个上游的SecurityFilterChain,下游的SecurityFilterChain就不会再进行匹配。

Spring Security 整体结构概览_第5张图片

有哪些Security Filter?

官方文档给出了按照Spring Security Filter排列顺序的列表:

Security Filters

处理安全异常

ExceptionTranslationFilter允许将AccessDeniedExceptionAuthenticationException异常转换为HTTP响应,从它的名字可以看到,它也是一个Filter,可以被插入到SecurityFilterChain中,这是它的工作流程:

Spring Security 整体结构概览_第6张图片

  1. 它调用下层的Filter处理请求
  2. 如果下层Filter抛出AuthenticationException,则会被它捕获(见下面代码),并调用它的startAuthentication()方法跳转进行认证。(图中的SecurityContextHolder等几个东西属于认证功能部分,可以先不用管)
  3. 如果下层Filter抛出AccessDeniedException则对异常作出响应,通知用户禁止访问。

总结

从上面可以看到,Spring Security的功能是通过Filter来实现的。每个Filter都是一个Bean,用户通过配置不同的Filter或自行实现Filter来达到保护应用/认证/授权等目的,不同的Filter组成了多个FilterChain,来实现不同的要求。

参考资料:Spring Security Reference - Version 5.3.2.RELEASE

你可能感兴趣的:(spring,spring-security,java,后端)