SpringSecurity学习日记(底层架构篇)

SpringSecurity

基本功能

SpringSecurity提供三个基本的功能

  • Authentication(身份认证)
  • Authenrization(用户授权)
  • 防御常见攻击

默认行为

  • 保护应用程序URL,要求对应用程序的任何交互进行身份验证
  • 程序启动时生成一个默认用户“user”
  • 生成一个默认的随机密码,并将此密码记录在控制台上
  • 生成默认的登录表单和注销页面
  • 提供基于表单的登录和注销流程
  • 对于web请求,重定向到登录页面
  • 对于服务请求,返回401未经授权
  • 处理跨站请求伪造(CSRF)攻击
  • 处理会话劫持攻击
  • 写入Strict-Transport-Security以确保HTTPS
  • 写入X-Content-Type-0ptions以处理嗅探攻击
  • 写入Cache Control头来保护经过身份验证的资源
  • 写入X-Frame-0ptions以处理点击劫持攻击。

架构

Spring Security 对 Servlet 的支持是基于Servlet过滤器的,所以先看一下过滤器的一般作用是很有帮助的
在这里插入图片描述

我们可以为拦截器链(Filter Chain)注册多个Filter,标准的Filter能完成防止下游的 Filter 实例或 Servlet 被调用或修改下游的 Filter 实例和 Servlet 所使用的 HttpServletRequest 或 HttpServletResponse的工作
由于一个 Filter 只影响下游的 Filter 实例和 Servlet,所以每个 Filter 的调用顺序是非常重要的。

Spring Security 的核心思想是拦截器链(Filter Chain)。当一个请求进入 Spring 应用程序时,它会经过一系列的过滤器。Spring Security 将自己的安全逻辑作为这些过滤器的一部分插入到请求处理流程中。
Spring Security 提供了一个名为 DelegatingFilterProxy 的 Filter 实现,允许在 Servlet 容器的生命周期和 Spring 的 ApplicationContext 之间建立桥梁,将标准的 Servlet 过滤器链与 Spring 的应用上下文(ApplicationContext)连接起来。

为什么需要 DelegatingFilterProxy?
理解 DelegatingFilterProxy 的必要性,需要先了解 Servlet 容器和 Spring 容器之间的区别:

Servlet 容器 (Web 容器):

  • 负责加载和管理标准的 Servlet 和 Filter。
  • 它通过 web.xml 配置或 @WebFilter 注解来识别和实例化过滤器。
  • Servlet 容器直接管理这些过滤器的生命周期(init()、doFilter()、destroy())。
  • 缺点:Web 容器实例化和管理的过滤器是普通的 Java 对象,它们不在 Spring 容器的管理之下。这意味着这些过滤器不能直接注入 Spring Bean,不能利用 Spring 的依赖注入、事务管理等高级功能。

Spring 容器 (ApplicationContext):

  • 负责管理 Spring Bean 的生命周期和依赖注入。
  • Spring Security 的核心组件(如 FilterChainProxy,它包含了所有的安全过滤器)都是 Spring Bean。

因此衍生出另外一个问题:
Spring Security 的安全过滤器链 (FilterChainProxy) 是一个 Spring Bean,它需要被 Spring 容器管理才能利用依赖注入等功能。但是,Web 容器只认识标准的 Servlet Filter。如何让 Web 容器调用的过滤器,实际上是 Spring 容器中的一个 Bean 呢?
这便是 DelegatingFilterProxy 的用武之地。

DelegatingFilterProxy 的工作流程

  1. Web 容器加载 DelegatingFilterProxy:
    你需要在 web.xml 中配置 DelegatingFilterProxy,或者使用 Spring Boot 自动配置。Web 容器会像加载任何其他 Servlet Filter 一样加载并初始化 DelegatingFilterProxy。
    在 web.xml 中,通常会这样配置:
<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>

这里的 filter-name (例如 springSecurityFilterChain) 是关键,它告诉 DelegatingFilterProxy 去 Spring 容器中寻找同名的 Bean。

  1. DelegatingFilterProxy 查找 Spring Bean:
    当 DelegatingFilterProxy 的 init() 方法被调用时,它不会像普通过滤器那样直接执行业务逻辑。
    相反,它会利用 Spring 的 WebApplicationContextUtils 或其他机制,找到当前 Web 应用对应的 Spring ApplicationContext。
    然后,它会根据其配置的 filter-name(例如 springSecurityFilterChain),从 Spring ApplicationContext 中查找对应的 Bean。
    在 Spring Security 中,这个 Bean 通常就是 org.springframework.security.web.FilterChainProxy 的实例。FilterChainProxy 是 Spring Security 自己的核心过滤器,它内部管理着一系列的 Spring Security 过滤器。

  2. 请求委托:
    当一个请求到达 DelegatingFilterProxy 的 doFilter() 方法时,DelegatingFilterProxy 会将这个请求委托给它在 Spring 容器中找到的那个 Bean(即 FilterChainProxy)。
    也就是说,DelegatingFilterProxy 只是一个“占位符”或“入口”,实际的过滤逻辑是由 Spring 容器中的 FilterChainProxy 来执行的。

  3. Spring Security 过滤器链执行:
    一旦请求被委托给 FilterChainProxy,FilterChainProxy 就会按照其内部配置的顺序,依次调用 Spring Security 自己的过滤器(如 UsernamePasswordAuthenticationFilter、FilterSecurityInterceptor 等)。这些过滤器都是 Spring Bean,因此可以充分利用 Spring 的功能。

在这里插入图片描述

FilterChainProxy 的工作原理

FilterChainProxy 是 Spring Security 的核心组件之一,它是一个特殊的 Servlet Filter,但它本身并不直接处理安全逻辑。它的主要职责是管理和调度 Spring Security 内部的多个 SecurityFilterChain 实例,并根据当前的请求 URL 路径,将请求分派给匹配的 SecurityFilterChain 进行处理。
可以把 FilterChainProxy 理解为一个路由器调度器,它位于整个 Spring Security 过滤器链的最顶层。

为什么需要FilterChainProxy?
在一个复杂的应用中,你可能希望对不同的 URL 模式应用不同的安全规则。例如:

  • /api/** 路径可能需要基于 Token 的认证和特定的 API 权限。
  • /admin/** 路径可能需要基于会话的表单认证和管理员角色。
  • /public/** 路径可能完全不需要认证。
    FilterChainProxy 允许你定义多个 SecurityFilterChain,每个链对应不同的 URL 模式和安全配置。

FilterChainProxy 的工作流程

  1. 被 DelegatingFilterProxy 调用
  2. 匹配 SecurityFilterChain:
    • FilterChainProxy 内部维护着一个有序的 List。
    • 当 FilterChainProxy 接收到请求后,它会遍历这个 SecurityFilterChain 列表。
    • 对于列表中的每一个 SecurityFilterChain,它会检查该链的 RequestMatcher 是否与当前请求的 URL 路径匹配。FilterChainProxy 会选择第一个匹配成功的 SecurityFilterChain 来处理请求。一旦找到匹配的链,就会停止遍历。
    • 执行匹配的 SecurityFilterChain
  3. 请求继续或终止:
    • 如果 SecurityFilterChain 中的所有过滤器都成功执行,请求最终会到达目标 Servlet 或 Controller。
    • 如果在任何一个安全过滤器中,认证失败、授权失败或发生了其他安全异常,请求可能会被终止,并根据配置重定向到登录页面、访问拒绝页面,或返回错误状态码。

在这里插入图片描述

SecurityFilterChain

在 Spring Security 中,SecurityFilterChain 是一个核心概念,它代表着一个特定的、有序的 Spring Security 过滤器集合,这些过滤器被应用到一组匹配的请求路径上。简单来说,SecurityFilterChain 定义了针对特定 URL 模式的一套安全规则和处理流程。

SecurityFilterChain 的组成

每个 SecurityFilterChain 主要由**RequestMatcher (请求匹配器)List (过滤器列表)**两部分组成

SecurityFilterChain 的工作流程
  • 一旦某个 SecurityFilterChain 被选中,FilterChainProxy 就会将请求和响应对象传递给该 SecurityFilterChain 内部的过滤器列表。
  • 接着,这个列表中的所有过滤器会按它们定义的顺序依次执行。
  • 每个过滤器在执行完自己的逻辑后,会调用 chain.doFilter(request, response) 将请求传递给链中的下一个过滤器。
  • 如果某个过滤器判断请求不符合安全要求(例如,用户未认证或无权限),它可能会直接生成错误响应、重定向到登录页,或者抛出异常,从而中断过滤器链的执行,请求就不会再传递到后续的过滤器或目标 Controller。
配置 SecurityFilterChain
@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/public/**").permitAll() // 允许访问 /public 下的所有资源
                .requestMatchers("/admin/**").hasRole("ADMIN") // /admin 下的资源需要 ADMIN 角色
                .anyRequest().authenticated() // 其他所有请求都需要认证
            )
            .formLogin(withDefaults()); // 启用表单登录

        return http.build();
    }

    // 可以定义多个 SecurityFilterChain Bean,通过它们的顺序和 RequestMatcher 来区分
    // @Bean
    // @Order(1) // 确保这个链优先处理
    // public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
    //     http
    //         .securityMatcher("/api/**") // 仅对 /api/** 路径生效
    //         .authorizeHttpRequests(authorize -> authorize
    //             .anyRequest().hasRole("API_USER") // /api/** 需要 API_USER 角色
    //         )
    //         .httpBasic(withDefaults()); // 为 /api/** 启用 HTTP Basic 认证
    //     return http.build();
    // }
}

在上述示例中,filterChain 方法返回的 SecurityFilterChain 对象就是由 FilterChainProxy 管理的一个独立的安全过滤器链。HttpSecurity 提供了便捷的 API 来配置这个链内部的各种安全行为和过滤器。

总结

Spring Security 并没有将它内部的每一个安全过滤器都直接暴露给 Web 容器去管理。相反,它设计了一个中央调度器——FilterChainProxy。这个 FilterChainProxy 自己作为一个 Spring Bean,并由 DelegatingFilterProxy 这个“中介”间接地被 Web 容器调用。一旦请求到达 FilterChainProxy,它就会根据请求的 URL,智能地选择并执行由其内部管理的、为特定路径配置好的那一串(SecurityFilterChain)安全过滤器(它们也都是 Spring Bean)。这种设计带来了极大的灵活性、可维护性和强大的调试能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值