Skip to content

Spring Security 核心架构

很多人一听到 Spring Security 就头大,主要原因不是它难,而是它内部链路比较长。

这章先不急着写代码,我们先把它的“大脑”和“骨架”看清楚。

Spring Security 是干什么的

它主要解决两类问题:

  1. 你是谁。
  2. 你能做什么。

第一类叫认证,英文是 Authentication。

第二类叫授权,英文是 Authorization。

先区分认证和授权

认证

确认当前请求对应的用户身份。

比如:

  1. 用户名密码登录。
  2. 手机验证码登录。
  3. Token 登录。
  4. OAuth2 第三方登录。

授权

确认这个用户是否有权限访问某个资源。

比如:

  1. 只有管理员能删除文章。
  2. 普通用户只能修改自己的资料。
  3. 游客只能看公开内容。

核心处理流程

mermaid
flowchart TD
    A[用户发起请求] --> B[进入过滤器链]
    B --> C[解析登录信息]
    C --> D[构建 Authentication]
    D --> E[交给 AuthenticationManager]
    E --> F[认证成功后写入 SecurityContext]
    F --> G[继续访问 Controller]
    G --> H[执行授权判断]
    H --> I[允许访问]
    H --> J[拒绝访问]

为什么它看起来“全是过滤器”

因为 Web 安全本身就非常适合放在请求进入业务前统一处理。

Spring Security 通过一条过滤器链,把很多安全动作串起来:

  1. 是否需要登录。
  2. 是否有 Token。
  3. Token 是否有效。
  4. 当前用户权限是什么。
  5. 是否允许访问当前接口。

最关键的几个角色

1. SecurityFilterChain

这是整个安全过滤规则的总入口。

你可以把它理解成:

哪些请求要拦,拦了之后按什么顺序做安全处理。

2. Authentication

表示“当前认证信息”的对象。

它通常包含:

  1. 当前用户是谁。
  2. 凭证是什么。
  3. 权限列表是什么。
  4. 是否已认证。

3. AuthenticationManager

负责真正执行认证逻辑。

它并不直接查库,而是把认证任务交给合适的 Provider。

4. AuthenticationProvider

真正的认证执行者。

比如:

  1. 用户名密码认证 Provider。
  2. 短信验证码认证 Provider。
  3. 自定义 Token 认证 Provider。

5. UserDetailsService

负责按用户名加载用户信息。

很多项目里,这一步会去数据库查:

  1. 用户基本信息。
  2. 角色列表。
  3. 权限列表。

6. SecurityContext

安全上下文,可以理解成“当前请求的安全身份盒子”。

认证成功后,当前用户信息会被放进去,后续授权、业务代码都能取到。

一次用户名密码登录内部发生了什么

mermaid
sequenceDiagram
    participant U as 用户
    participant F as 认证过滤器
    participant M as AuthenticationManager
    participant P as Provider
    participant S as UserDetailsService
    participant DB as 数据库

    U->>F: 提交用户名和密码
    F->>M: 发起认证
    M->>P: 选择合适 Provider
    P->>S: 按用户名查用户
    S->>DB: 查询用户和权限
    DB-->>S: 返回用户数据
    S-->>P: 返回 UserDetails
    P->>P: 校验密码
    P-->>M: 返回认证成功结果
    M-->>F: 返回 Authentication
    F->>F: 写入 SecurityContext

401 和 403 的区别

这是初学者非常容易混的点。

401

表示你还没有通过认证,或者认证信息无效。

简单理解:

你还没证明你是谁。

403

表示你已经登录了,但你没有这个权限。

简单理解:

我知道你是谁,但你不能访问这里。

为什么 Spring Security 容易“看不懂报错”

因为它的逻辑并不是在 Controller 里报错,而是在过滤器链前面就拦下来了。

所以你会看到:

  1. 请求根本进不了 Controller。
  2. 直接返回 401/403。
  3. 日志里出现一堆过滤器和认证类。

这不是异常,而是它的正常工作方式。

对博客项目来说最常见的安全场景

  1. 后台登录。
  2. 管理员权限控制。
  3. 文章接口游客可读、后台可写。
  4. Token 鉴权。
  5. 密码加密存储。
  6. 未登录和无权限的统一返回。

本章小结

Spring Security 的学习关键不是先背 API,而是先记住它的主线:

  1. 请求先过过滤器链。
  2. 过滤器负责提取认证信息。
  3. 认证管理器负责确认身份。
  4. 成功后写入安全上下文。
  5. 再根据权限判断能不能访问资源。

这条主线清楚后,后面的登录流程和权限控制就不再是黑盒。

代码 Demo:自定义 Token 过滤器骨架

下面示例演示 Token 过滤器在过滤器链中的职责:解析 Token,构建认证信息,写入 SecurityContext

java
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain)
            throws ServletException, IOException {
        String token = request.getHeader("Authorization");

        if (token != null && token.startsWith("Bearer ")) {
            String username = parseUsername(token.substring(7));
            List<GrantedAuthority> authorities = List.of(
                new SimpleGrantedAuthority("article:create")
            );

            Authentication authentication =
                new UsernamePasswordAuthenticationToken(username, null, authorities);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        chain.doFilter(request, response);
    }
}

真实项目中 parseUsername 必须校验签名、过期时间和黑名单,不能只解析不校验。