Spring Security 核心架构
很多人一听到 Spring Security 就头大,主要原因不是它难,而是它内部链路比较长。
这章先不急着写代码,我们先把它的“大脑”和“骨架”看清楚。
Spring Security 是干什么的
它主要解决两类问题:
- 你是谁。
- 你能做什么。
第一类叫认证,英文是 Authentication。
第二类叫授权,英文是 Authorization。
先区分认证和授权
认证
确认当前请求对应的用户身份。
比如:
- 用户名密码登录。
- 手机验证码登录。
- Token 登录。
- OAuth2 第三方登录。
授权
确认这个用户是否有权限访问某个资源。
比如:
- 只有管理员能删除文章。
- 普通用户只能修改自己的资料。
- 游客只能看公开内容。
核心处理流程
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 通过一条过滤器链,把很多安全动作串起来:
- 是否需要登录。
- 是否有 Token。
- Token 是否有效。
- 当前用户权限是什么。
- 是否允许访问当前接口。
最关键的几个角色
1. SecurityFilterChain
这是整个安全过滤规则的总入口。
你可以把它理解成:
哪些请求要拦,拦了之后按什么顺序做安全处理。
2. Authentication
表示“当前认证信息”的对象。
它通常包含:
- 当前用户是谁。
- 凭证是什么。
- 权限列表是什么。
- 是否已认证。
3. AuthenticationManager
负责真正执行认证逻辑。
它并不直接查库,而是把认证任务交给合适的 Provider。
4. AuthenticationProvider
真正的认证执行者。
比如:
- 用户名密码认证 Provider。
- 短信验证码认证 Provider。
- 自定义 Token 认证 Provider。
5. UserDetailsService
负责按用户名加载用户信息。
很多项目里,这一步会去数据库查:
- 用户基本信息。
- 角色列表。
- 权限列表。
6. SecurityContext
安全上下文,可以理解成“当前请求的安全身份盒子”。
认证成功后,当前用户信息会被放进去,后续授权、业务代码都能取到。
一次用户名密码登录内部发生了什么
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: 写入 SecurityContext401 和 403 的区别
这是初学者非常容易混的点。
401
表示你还没有通过认证,或者认证信息无效。
简单理解:
你还没证明你是谁。
403
表示你已经登录了,但你没有这个权限。
简单理解:
我知道你是谁,但你不能访问这里。
为什么 Spring Security 容易“看不懂报错”
因为它的逻辑并不是在 Controller 里报错,而是在过滤器链前面就拦下来了。
所以你会看到:
- 请求根本进不了 Controller。
- 直接返回 401/403。
- 日志里出现一堆过滤器和认证类。
这不是异常,而是它的正常工作方式。
对博客项目来说最常见的安全场景
- 后台登录。
- 管理员权限控制。
- 文章接口游客可读、后台可写。
- Token 鉴权。
- 密码加密存储。
- 未登录和无权限的统一返回。
本章小结
Spring Security 的学习关键不是先背 API,而是先记住它的主线:
- 请求先过过滤器链。
- 过滤器负责提取认证信息。
- 认证管理器负责确认身份。
- 成功后写入安全上下文。
- 再根据权限判断能不能访问资源。
这条主线清楚后,后面的登录流程和权限控制就不再是黑盒。
代码 Demo:自定义 Token 过滤器骨架
下面示例演示 Token 过滤器在过滤器链中的职责:解析 Token,构建认证信息,写入 SecurityContext。
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 必须校验签名、过期时间和黑名单,不能只解析不校验。
