一、核心架构:过滤器链 (Filter Chain)
Spring Security 的本质是一条 Servlet 过滤器链 (Filter Chain) 。它在请求到达 Spring MVC 的 DispatcherServlet 之前 就开始工作。
整体流程如下:

关键点 :Security 的所有工作都在
DispatcherServlet之前完成。
二、Spring Security 认证 (Authentication) 详细过程
认证的目标是回答 "你是谁?" 的问题。
-
请求拦截:
- 用户访问一个受保护的资源(例如
/api/user/profile)。 - 请求首先被
DelegatingFilterProxy拦截,并委托给 Spring Security 的FilterChainProxy。
- 用户访问一个受保护的资源(例如
-
凭证提取:
- 在你的自定义
JwtAuthenticationFilter(通常继承OncePerRequestFilter) 中,从请求头(如Authorization: Bearer <token>)中提取 JWT Token。
- 在你的自定义
-
凭证验证:
- 调用 JWT 工具类(如
jjwt库)验证 Token 的签名、有效期等。 - 如果 Token 无效、过期或缺失,不进行任何操作,直接放行到下一个 Filter。
- 调用 JWT 工具类(如
-
身份构建:
- 如果 Token 有效,从中解析出用户标识(如
username或userId)。 - 调用
UserDetailsService.loadUserByUsername()加载完整的用户信息和权限(UserDetails对象)。 - 基于这些信息,创建一个已认证的
Authentication对象(通常是UsernamePasswordAuthenticationToken)。
- 如果 Token 有效,从中解析出用户标识(如
-
上下文存储:
- 将这个
Authentication对象存入SecurityContext。 SecurityContextHolder.getContext().setAuthentication(authentication);- 这个上下文会在线程内共享,供后续的授权检查使用。
- 将这个
-
继续流程:
- 请求继续沿着 Filter 链向下传递。
三、Spring Security 授权 (Authorization) 与 Spring MVC 的协作
授权的目标是回答 "你能做什么?" 的问题。
-
授权检查:
- 在 Filter 链的末尾,
FilterSecurityInterceptor会根据你在HttpSecurity中配置的规则(如.anyRequest().authenticated()或.requestMatchers("/admin/**").hasRole("ADMIN"))进行授权检查。 - 它会检查
SecurityContext中是否存在有效的Authentication对象及其权限。
- 在 Filter 链的末尾,
-
决策点:
- 情况 A:未通过认证/授权
- 如果
SecurityContext为空(未登录)或权限不足,ExceptionTranslationFilter会捕获AccessDeniedException或AuthenticationException。 - 然后,它会调用你配置的
AuthenticationEntryPoint(处理 401) 或AccessDeniedHandler(处理 403)。 - 此时,请求根本不会到达
DispatcherServlet! 所以你看到的是401,而不是404。
- 如果
- 情况 B:通过认证/授权
- 请求成功通过整个 Security Filter 链。
- 请求终于到达
DispatcherServlet。
- 情况 A:未通过认证/授权
-
Spring MVC 处理:
DispatcherServlet开始工作,尝试根据 URL 找到匹配的@Controller和@RequestMapping。- 如果找到:执行 Controller 逻辑,返回正常响应。
- 如果找不到 :抛出
NoHandlerFoundException。 - 这个异常会被你的
@ControllerAdvice全局异常处理器 (GlobalExceptionHandler) 捕获,并格式化为404JSON 响应。
四、关键注意点与最佳实践
-
安全优先原则:
- 永远不要为了"先看 404"而绕过 Security 。这会泄露 API 结构,带来严重安全风险。
401for unauthenticated 是正确且安全的行为。
- 永远不要为了"先看 404"而绕过 Security 。这会泄露 API 结构,带来严重安全风险。
-
明确划分公开/私有接口:
- 在
HttpSecurity配置中,清晰地使用permitAll()放行登录、注册、健康检查等公开接口。 - 使用
authenticated()或更细粒度的权限控制保护其他所有接口。
- 在
-
全局异常处理的职责分离:
- Security 层异常 (
AuthenticationException,AccessDeniedException):由 Security 自己的EntryPoint和AccessDeniedHandler处理,返回401/403。 - MVC 层异常 (
NoHandlerFoundException,MethodArgumentNotValidException):由@ControllerAdvice处理,返回404/400等。 - 业务层异常 :也由
@ControllerAdvice处理。
- Security 层异常 (
-
无状态认证 (JWT) 的要点:
- 不要使用 Session :确保
HttpSecurity配置了.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)。 - 每次请求都验证 :在自定义 Filter 中,对每个请求都重新验证 Token 并重建
SecurityContext。
- 不要使用 Session :确保
-
CORS 与 CSRF:
- 前后端分离项目:务必正确配置 CORS。
- 无状态 API (JWT) :通常需要禁用 CSRF 保护,因为客户端无法安全地存储和发送 CSRF Token。
.csrf().disable()。
-
密码安全:
- 永远不要明文存储密码。必须使用
PasswordEncoder(如BCryptPasswordEncoder) 进行加密。
- 永远不要明文存储密码。必须使用
-
测试策略:
- 测试
404时,务必使用有效的 Token。这是验证你的全局异常处理器是否工作的唯一正确方式。
- 测试
