Spring Security 与 Spring MVC

一、核心架构:过滤器链 (Filter Chain)

Spring Security 的本质是一条 Servlet 过滤器链 (Filter Chain) 。它在请求到达 Spring MVC 的 DispatcherServlet 之前 就开始工作。

整体流程如下:

关键点 :Security 的所有工作都在 DispatcherServlet 之前完成。


二、Spring Security 认证 (Authentication) 详细过程

认证的目标是回答 "你是谁?" 的问题。

  1. 请求拦截

    • 用户访问一个受保护的资源(例如 /api/user/profile)。
    • 请求首先被 DelegatingFilterProxy 拦截,并委托给 Spring Security 的 FilterChainProxy
  2. 凭证提取

    • 在你的自定义 JwtAuthenticationFilter (通常继承 OncePerRequestFilter) 中,从请求头(如 Authorization: Bearer <token>)中提取 JWT Token。
  3. 凭证验证

    • 调用 JWT 工具类(如 jjwt 库)验证 Token 的签名、有效期等。
    • 如果 Token 无效、过期或缺失,不进行任何操作,直接放行到下一个 Filter。
  4. 身份构建

    • 如果 Token 有效,从中解析出用户标识(如 usernameuserId)。
    • 调用 UserDetailsService.loadUserByUsername() 加载完整的用户信息和权限(UserDetails 对象)。
    • 基于这些信息,创建一个已认证的 Authentication 对象(通常是 UsernamePasswordAuthenticationToken)。
  5. 上下文存储

    • 将这个 Authentication 对象存入 SecurityContext
    • SecurityContextHolder.getContext().setAuthentication(authentication);
    • 这个上下文会在线程内共享,供后续的授权检查使用。
  6. 继续流程

    • 请求继续沿着 Filter 链向下传递。

三、Spring Security 授权 (Authorization) 与 Spring MVC 的协作

授权的目标是回答 "你能做什么?" 的问题。

  1. 授权检查

    • 在 Filter 链的末尾,FilterSecurityInterceptor 会根据你在 HttpSecurity 中配置的规则(如 .anyRequest().authenticated().requestMatchers("/admin/**").hasRole("ADMIN"))进行授权检查。
    • 它会检查 SecurityContext 中是否存在有效的 Authentication 对象及其权限。
  2. 决策点

    • 情况 A:未通过认证/授权
      • 如果 SecurityContext 为空(未登录)或权限不足,ExceptionTranslationFilter 会捕获 AccessDeniedExceptionAuthenticationException
      • 然后,它会调用你配置的 AuthenticationEntryPoint (处理 401) 或 AccessDeniedHandler (处理 403)。
      • 此时,请求根本不会到达 DispatcherServlet 所以你看到的是 401,而不是 404
    • 情况 B:通过认证/授权
      • 请求成功通过整个 Security Filter 链。
      • 请求终于到达 DispatcherServlet
  3. Spring MVC 处理

    • DispatcherServlet 开始工作,尝试根据 URL 找到匹配的 @Controller@RequestMapping
    • 如果找到:执行 Controller 逻辑,返回正常响应。
    • 如果找不到 :抛出 NoHandlerFoundException
    • 这个异常会被你的 @ControllerAdvice 全局异常处理器 (GlobalExceptionHandler) 捕获,并格式化为 404 JSON 响应。

四、关键注意点与最佳实践

  1. 安全优先原则

    • 永远不要为了"先看 404"而绕过 Security 。这会泄露 API 结构,带来严重安全风险。401 for unauthenticated 是正确且安全的行为。
  2. 明确划分公开/私有接口

    • HttpSecurity 配置中,清晰地使用 permitAll() 放行登录、注册、健康检查等公开接口。
    • 使用 authenticated() 或更细粒度的权限控制保护其他所有接口。
  3. 全局异常处理的职责分离

    • Security 层异常 (AuthenticationException, AccessDeniedException):由 Security 自己的 EntryPointAccessDeniedHandler 处理,返回 401/403
    • MVC 层异常 (NoHandlerFoundException, MethodArgumentNotValidException):由 @ControllerAdvice 处理,返回 404/400 等。
    • 业务层异常 :也由 @ControllerAdvice 处理。
  4. 无状态认证 (JWT) 的要点

    • 不要使用 Session :确保 HttpSecurity 配置了 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    • 每次请求都验证 :在自定义 Filter 中,对每个请求都重新验证 Token 并重建 SecurityContext
  5. CORS 与 CSRF

    • 前后端分离项目:务必正确配置 CORS。
    • 无状态 API (JWT) :通常需要禁用 CSRF 保护,因为客户端无法安全地存储和发送 CSRF Token。.csrf().disable()
  6. 密码安全

    • 永远不要明文存储密码。必须使用 PasswordEncoder (如 BCryptPasswordEncoder) 进行加密。
  7. 测试策略

    • 测试 404 时,务必使用有效的 Token。这是验证你的全局异常处理器是否工作的唯一正确方式。
相关推荐
lemon_sjdk16 小时前
WCPoint、WebPageClient和Accessor类源码
java·安全·webkit·javafx
vx-Biye_Design16 小时前
springboot中国传统节日宣传平台49078-计算机课程设计、毕业设计
java·前端·vue.js·spring boot·后端·课程设计·idea
野生技术架构师17 小时前
从向量检索到混合搜索优化:Spring AI 2.0.1 + pgvector RAG 实战
java·人工智能·spring
IT枫斗者枫哥17 小时前
CompletableFuture 超时了,任务还在跑?用三个实验分清超时与取消
java
chushiyunen17 小时前
mockito笔记
java·开发语言·笔记
Doubbbbbbble云17 小时前
基于空间局部性的排序算法性能重构思路4
java·重构·排序算法
MetaLite18 小时前
Java 时间处理的两个坑:单位误判,半秒算成一秒
java·开发语言·前端
黄骨鱼骨18 小时前
DatI:给AI接入数据库,Agent时代的NL2SQL问数与多维表格应该怎么做
java·database·text2sql·nl2sql·chatbi·mcp·data agent
Wang's Blog18 小时前
Java框架快速入门: Spring Security+OAuth2之实现UserDetails与GrantedAuthority深度定制
java·spring·mybatis
Amberish18 小时前
26Java细节知识点总结
java