TW

// post

SpringBoot 3 中 JWT 鉴权的正确实现方式

很多项目的 JWT 实现都存在同一个问题:无法主动失效。本文从登录态的本质出发,讲清无状态鉴权的边界与补救方案。

2026.05.28·3 min read·1286 views

问题:你的 JWT 能"踢人下线"吗

几乎所有 JWT 教程都止步于"生成 token 并通过过滤器校验"。但真实业务里很快就会遇到一个需求:强制某个用户下线。

此时纯无状态方案会暴露它的边界——签发过的 token 在过期前始终有效,服务端没有撤销手段。

无状态鉴权到底牺牲了什么

JWT 的核心优势是把会话状态从服务端搬到客户端,换来的是水平扩展的便利。代价就是丧失了服务端的会话控制权。

判断标准其实很简单:

场景适合纯 JWT需要会话控制
内部工具、短期接口✅
需要强制下线的 C 端✅
权限频繁变更✅
微服务间内部调用✅

补救方案一:缩短有效期 + 刷新令牌

public record TokenPair(String accessToken, String refreshToken) {}

public TokenPair issue(User user) {
    String access = Jwts.builder()
        .subject(user.getId().toString())
        .claim("role", user.getRole())
        .issuedAt(new Date())
        .expiration(Date.from(Instant.now().plus(15, ChronoUnit.MINUTES)))
        .signWith(key)
        .compact();

    String refresh = randomToken();               // 刷新令牌存库,可撤销
    refreshStore.save(user.getId(), refresh, Duration.ofDays(7));
    return new TokenPair(access, refresh);
}

访问令牌只活 15 分钟,撤销时只需删除刷新令牌。窗口期小到可接受。

补救方案二:加一层黑名单

如果业务要求"立即生效",就得引入状态。用 Redis 存被撤销的 token 标识,成本很低:

public boolean isRevoked(String jwtId) {
    return redis.hasKey("jwt:revoked:" + jwtId);
}

public void revoke(String jwtId, Duration ttl) {
    // TTL 设为 token 剩余有效期,过期自动清理
    redis.opsForValue().set("jwt:revoked:" + jwtId, "1", ttl);
}

落地建议

  1. 访问令牌有效期控制在 15–30 分钟
  2. 刷新令牌入库,支持撤销
  3. 权限敏感的接口额外做一次实时校验
  4. 不要在 JWT 里放敏感信息,它是可解码的,不是加密的

小结

没有万能方案。先把业务对"会话控制"的要求想清楚,再决定用纯无状态还是混合方案。很多项目的问题不是选错了技术,而是没意识到选型时牺牲了什么。

本文为 探微编程原创,转载请注明出处

// contact

有需求?先聊聊你的项目

不管是一次技术支持、一个完整项目,还是想补一段工程能力,都可以先沟通。我们会先了解需求并给出判断,再谈方案与报价。

wechat
Trdfyl
qq
2356245930
探微编程 微信二维码

扫码添加微信