Spring Security JWT 验证失败返回 401 Unauthorized 怎么排查?

文章导读
Spring Security JWT 验证失败返回 401 通常是因为请求头缺失、Token 过期或安全配置拦截了公开接口。排查时优先检查 Authorization 请求头格式,确认 SecurityFilterChain 中公开路径配置,最后验证 JwtAuthenticationEntryPoint 异常处理逻辑。
📋 目录
  1. 快速处理思路
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

Spring Security JWT 验证失败返回 401 通常是因为请求头缺失、Token 过期或安全配置拦截了公开接口。排查时优先检查 Authorization 请求头格式,确认 SecurityFilterChain 中公开路径配置,最后验证 JwtAuthenticationEntryPoint 异常处理逻辑。

先说结论:401 错误代表未认证,需按请求头、安全配置、 Token 有效性顺序排查。

  • 先确认:请求头是否包含 Bearer 前缀且拼写正确。
  • 先处理:放行/error 路径及登录接口,避免拦截链误杀。
  • 再验证:查看后台日志确认是 Token 过期还是签名验证失败。

快速处理思路

Java 项目无法直接使用 shell 命令止血,但可通过调整配置快速定位。优先检查前端请求头是否携带 Token,其次确认后端安全配置是否放行了无需认证的路径。

// 检查前端请求头格式
Authorization: Bearer <your_token>

// 检查 SecurityConfig 配置
http.authorizeHttpRequests(auth -> auth
    .requestMatchers("/public/**", "/error").permitAll()
    .anyRequest().authenticated()
);

为什么会这样

Spring Security 通过过滤器链拦截请求,认证失败时由 AuthenticationEntryPoint 统一返回 401。当请求未携带 Token 或 Token 无效时,过滤器链中断并将控制权交给入口点处理类。

JwtAuthenticationEntryPoint 是处理认证失败的核心类,当用户尝试访问受保护资源但未提供有效凭证时被触发,主要功能是向客户端返回 401 Unauthorized 响应。若配置不当,连系统错误路径/error 也会被拦截,导致原本应返回 404 的请求变成 401。

分步处理

按请求头、配置、逻辑三层顺序排查,每步操作后需重启应用验证。

1. 检查请求头格式

确认客户端发送的 Authorization 头符合 Bearer 格式。若头缺失或格式错误,直接返回 401。注意大小写兼容,推荐统一用小写 authorization。

Spring Security JWT 验证失败返回 401 Unauthorized 怎么排查?
const authHeader = req.headers.authorization || req.headers.Authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ message: 'Access denied' });
}

2. 修正安全配置

在 SecurityFilterChain 中显式放行公开路径和错误路径。Spring Boot 内部会将异常转发至/error,若该路径未放行,会触发认证拦截。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(auth -> auth
        .requestMatchers("/authentication/login", "/error").permitAll()
        .anyRequest().authenticated()
    );
    return http.build();
}

3. 排查组件扫描

若升级至 Spring Security 6.x,检查@SpringBootApplication 是否限制了 scanBasePackages。若安全组件不在扫描范围内,配置类不会加载,导致默认拦截所有请求。

4. 验证 Token 逻辑

检查 JWT 工具类的签名密钥是否一致,确认 Token 未过期。若使用微服务架构,确保 Feign 拦截器正确传递了 Token 至下游服务。

怎么验证是否生效

使用 Postman 或 curl 发送请求,观察状态码变化。同时查看控制台日志,确认是否有 AuthenticationException 抛出。

Spring Security JWT 验证失败返回 401 Unauthorized 怎么排查?

验证步骤:

  1. 发送不带 Token 的请求到公开接口,应返回 200。
  2. 发送不带 Token 的请求到受保护接口,应返回 401。
  3. 发送带有效 Token 的请求到受保护接口,应返回 200。
  4. 访问不存在路径,应返回 404 而非 401。

日志中若出现"Full authentication is required to access this resource",说明请求被拦截且未通过认证。

常见坑

1. 错误路径被拦截

访问不存在路径时,Spring Boot 转发至/error,若该路径未配置 permitAll,会返回 401 而不是 404。

2. 跨域预检请求失败

浏览器发送 OPTIONS 请求时若未携带 Token 且未放行,会被拦截导致跨域报错。需在安全配置中放行 OPTIONS 方法或对应路径。

Spring Security JWT 验证失败返回 401 Unauthorized 怎么排查?

3. 微服务 Token 丢失

服务间调用时,若 Feign 未配置拦截器传递 Authorization 头,下游服务会因缺少凭证返回 401。

4. 组件扫描遗漏

显式指定 scanBasePackages 时,若 JwtAuthenticationEntryPoint 等类不在扫描包下,配置不生效,导致所有请求被拦截。

常见问题

401 和 403 有什么区别?

401 表示未认证,即用户未登录或 Token 无效;403 表示已认证但无权限,即用户身份合法但角色不足。

为什么登录接口也返回 401?

登录接口未在 SecurityFilterChain 中配置 permitAll,被安全过滤器拦截。需将/login 等路径加入公开列表。

OPTIONS 请求被拦截怎么办?

在 authorizeHttpRequests 中放行 OPTIONS 方法,或配置 CORS 过滤器在安全过滤器链之前执行。

参考来源

  • JWT Spring Security Demo 异常处理机制:认证失败与权限不足的优雅处理
  • Spring Security 6+ 迁移中 401 错误的常见根源与修复指南
  • Spring Boot JWT 角色权限控制:解决 401 未授权问题
  • Spring Security 经典陷阱:访问不存在路径返回 401? 全版本解决方案
  • JWT Token 验证失败与请求头缺失问题的完整解决方案
  • springboot 整合了 security 之后无法返回 404 而是 401
  • Spring Cloud 微服务间调用遇 401?Feign 拦截器传递 Token 的实战解决方案