在配置资源服务器的时候,经常最简化的配置就是:
http.oauth2ResourceServer(oauth -> oauth.jwt(Customizer.withDefaults()))
这行代码底层主要配置了两大核心支柱:一个负责拦截,一个负责拆弹(解析 JWT)
1.BearerTokenAuthenticationFilter 负责拦截
在 OAuth2 资源服务器模式下,Spring Security 会在过滤器链中加入一个核心拦截器:BearerTokenAuthenticationFilter。
-
它的位置:通常在过滤器链的中后部。
-
它的职责:
- 扫描每个请求的 Header。
- 寻找
Authorization: Bearer <TOKEN>格式的头。 - 如果找到了,就把这一串长长的字符串(Token)提取出来,封装成一个
BearerTokenAuthenticationToken对象,交给后续处理。
BearerTokenAuthenticationFilter拦截逻辑如下:
2.JwtAuthenticationProvider 负责拆弹(解析 JWT)
上图封装的BearerTokenAuthenticationToken要交给AuthenticationManager进行认证,AuthenticationManager使用AuthenticationProvider来完成校验,JwtAuthenticationProvider就是AuthenticationProvider接口的实现类,用来解析token
JwtAuthenticationProvider的源码如下图:
getJwt 就是利用jwtDecoder来完成对token的解析,生成Jwt对象
利用JwtAuthenticationConverter,将Jwt对象转成最终的JwtAuthenticationToken
在这个过程中,底层还配置了一个权限转换器:JwtGrantedAuthoritiesConverter。
- 默认逻辑:它会去找 JWT Payload 里的
scp或scope字段。 - 结果:如果你的 JWT 里有
"scope": "read",那么在 Spring Security 内部,你的权限就会被自动转换成SCOPE_read。
如果不带token访问一个受保护的api会发生什么?
当你不带 Token 访问一个受保护的 API(如 /api/data)时,请求会流经过滤器链。
- 过滤器:
BearerTokenAuthenticationFilter - 动作:它尝试从请求头
Authorization中提取 Token。 - 结果:它发现 Header 是空的。此时它什么都不做只是简单地把请求传给下一个过滤器。因为它的职责只是“提取”,没有 Token 意味着“当前用户依然是匿名状态”。
请求继续往后走,直到遇见 AuthorizationFilter(这是过滤器链的最后一关,负责最终权限判定)。
- 逻辑:它发现你访问的是受保护资源,但目前的身份是
Anonymous(匿名)。 - 动作:抛出一个
AccessDeniedException(拒绝访问异常)。
这个访问异常会被**ExceptionTranslationFilter** 这个过滤器处理
这个过滤器内部持有一个关键组件:AuthenticationEntryPoint。 对于 OAuth2,它的默认实现类是:BearerTokenAuthenticationEntryPoint
AuthenticationEntryPoint见名知意引导用户去认证的入口,用户尝试访问一个受保护的资源但尚未认证(即未登录)时,决定如何“开始”认证流程。
而BearerTokenAuthenticationEntryPoint 专门用于 基于 Bearer Token(如 JWT)的无状态 REST API 认证场景
它的默认行为是:
返回 HTTP 状态码
401 Unauthorized,并在响应头中添加WWW-Authenticate: Bearer。
为什么会有 WWW-Authenticate: Bearer?
这是 RFC 6750 标准(OAuth 2.0 承载令牌)的规定。
• 含义:它在告诉客户端(比如你的前端 Vue 应用或 Postman):“这个资源是受保护的,你需要使用 Bearer Token 方案进行认证才能访问。”