跳转到内容

Spring Security + JWT:验签、授权与注销边界

JWT 可以让资源服务器在本地验证签名,减少对集中登录状态的查询。它不会自动解决注销、封禁或权限变更:如果每次只验签,已签发的 Token 通常会有效到过期;需要即时撤销,就要加入状态检查或其他撤销机制。

例如,用户被封禁后,旧 Token 仍能访问接口。缩短有效期只能缩短风险窗口;要求立即失效时,还要检查撤销记录,并阻止继续刷新。

检查作用
允许的签名算法与可信公钥防止伪造;不能信任 Token 自己指定的任意密钥来源
iss、aud、exp、nbf确认签发者、目标服务和有效时间
scope、角色与业务对象权限已认证不等于有权读取任意订单
撤销或账号状态按业务要求处理注销、封禁和权限变更

签名 JWT 的 payload 通常可以直接读,签名不是加密,不要放秘密。多服务部署常用非对称签名,让资源服务持有公钥却无法签发 Token;RSA 是一种选择,也可以按体系使用合适的 EC 等算法。HMAC 的验签方同时持有签发能力,需要更严格的信任边界。

引入依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

以下是配置示例,域名和 audience 换成自己的认证体系:

spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth.example.com
jwk-set-uri: https://auth.example.com/oauth2/jwks
audiences: https://api.example.com

同时指定 issuer 和 JWK Set URI,既能验证 iss,又不必通过发现端点获取 JWK 地址。公钥的获取、缓存和轮换按框架配置处理,不等于每次请求都查认证中心。较早的 Boot 版本若不支持 audiences 属性,用自定义 validator 校验 aud。Spring Security 官方文档

@Configuration
@EnableWebSecurity
public class ResourceServerConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 仅适用于凭证由客户端主动放入 Authorization 头的 API
.csrf(csrf -> csrf.disable())
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}

这是过滤链片段,省略 imports。默认 scope 映射为 SCOPE_ 权限;示例中的 hasRole("ADMIN") 要有明确的 ROLE_ADMIN 映射,不能以为 Token 带了 roles 字段就自动生效。

若浏览器会自动附带 Cookie 等认证凭证,仍需评估 CSRF;把 Refresh Token 放在 HttpOnly Cookie 中,只能减少脚本读取风险,刷新端点仍需保护。CSRF 官方说明

要求做法代价
允许短暂风险窗口短期 Access Token,刷新时检查账号状态注销后旧 Token 可能仍有效;15 分钟只是示例
撤销单个 Token用 jti 记录撤销,保留到其过期请求需查询撤销状态,所有可达入口都要执行
封禁整个账号校验账号状态或 Token 版本,并撤销刷新凭证不能仅把 userId 按某一个 Token 的剩余寿命过期
使用本地缓存减少查询明确最大缓存延迟与更新方式缓存会扩大撤销生效窗口,故障时放行还是拒绝也要定义

黑名单重新引入集中状态,其体积取决于实际撤销量,不能保证“小几个数量级”。共享 Session、Token introspection 和 JWT 都是可选方案;先确定失效时效与可用性要求,再选状态放在哪里。