资讯详情

JWT访问认证原理与Java落地:从无状态设计到Spring Boot实践

📅 2026/10/20 12:10:39 | 华诺云谱 👁 阅读
JWT访问认证原理与Java落地:从无状态设计到Spring Boot实践
1. 为什么越来越多的项目放弃 Session改用 JWT 做访问认证先说一个我印象特别深的排查经历。有个后台管理系统前端改成了单页应用后端接口也拆成了好几个微服务但登录状态还停留在传统的 Session Cookie 方案。联调阶段前端同事天天来问为什么同一个用户这次请求有登录信息下一次请求就没了查到最后发现是 Cookie 的跨域策略和域名不一致导致的还有微服务之间 Session 不共享的问题。那次之后我就在项目里全面换成了 JWT也就是 JSON Web Token用来做访问认证。这其实就是 JWT 最典型的落地场景前后端分离、接口服务化、需要无状态认证。JWT 的运行逻辑不复杂服务端在用户登录成功后签发一个经过签名的 token 给客户端客户端每次请求时把这个 token 放到请求头里带上服务端只需要验证签名是否有效就能确认请求来自哪个用户。整个过程中服务端不需要保存会话数据所以特别适合多实例部署和微服务架构。这篇文章我会把 JWT 访问认证从原理到 Java 落地完整讲一遍包括三部分结构拆解、签名验证机制、Spring Boot 里怎么签发和拦截令牌以及我在实际接入时踩过的坑和对应的工程化方案。适合刚接触 JWT 的后端开发也适合已经在用但想搞清楚内部细节、顺便排查安全隐患的同学。1.1 Session 方案在前后端分离场景下的几个痛点先别急着否定 Session它本身没有错在传统服务端渲染页面的时代是很好用的。问题出现在前后端分离之后。第一个痛点是存储问题。Session 默认存在服务端内存里单机部署没事一旦多实例部署用户的请求被负载均衡到另一台机器就找不到原来的 Session 了。常见的解决办法是引入 Redis 做集中式 Session 存储但这又带来额外的运维成本和一次网络开销。第二个痛点是跨域问题。单页应用通常跑在独立的域名下接口域名和后端域名可能不一致Cookie 的跨域携带规则非常麻烦很多团队的联调时间都耗在这个问题上了。为了解决跨域还得配 CORS、配 Cookie 的 SameSite 属性或者改域名结构一通操作下来只是为了维持一个登录态。第三个痛点是客户端的适配。移动端 App 对 Cookie 的支持不如浏览器友好开发者需要额外处理 Cookie 的存储、携带和安全策略。Session 设计之初并没有考虑这些非浏览器形态的客户端这导致很多团队在做 App 接口时都要做一套独立的认证方案一前一后两套逻辑维护成本很高。1.2 JWT 的无状态设计到底改变了什么JWT 的核心优势就是无状态。用户认证成功后服务端生成一个 token 返回给客户端后续所有请求只要在 Authorization 请求头里带上这个 token 即可。服务端自己不再保存任何登录态只需要对 token 的签名做一次校验判断它是不是由本服务签发、有没有过期就能确定用户身份。这个设计带来的直接收益是集群扩展变得非常简单。想加机器直接加就行不需要同步 Session 数据想按业务拆服务下游服务拿到 token 就能验签前提是它们共享同一份密钥或者能够验证签名。无状态还顺带解决了 Session 的跨域问题。因为 token 是放在自定义请求头里的不依赖 Cookie跨域时只需要配置一个普通的 CORS 允许 Authorization 头即可不用再折腾 Cookie 的跨域策略。移动端也一样把 token 存到本地存储里每次请求时手动拼上就行。我用下面这个表格总结一下两者的关键差异对比维度Session CookieJWT服务端存储需要存会话数据不需要纯无状态集群扩展要处理会话同步问题加机器即可跨域支持Cookie 跨域规则复杂请求头携带天然跨域移动端适配Cookie 适配麻烦普通请求头即可服务端主动注销支持删 Session 即可需要额外方案比如黑名单篡改风险Cookie 可被篡改需防伪签名机制天然防篡改所以我的建议是如果你的项目全部是服务端渲染页面、部署架构又是单体应用Session 完全够用但如果你的项目已经是前后端分离、接口拆了微服务、或者有 App 端接入JWT 绝对是更合适的选择。2. 拆开 JWT 看结构三部分各自负责什么很多教程上来就贴代码教你生成 token但我觉得不搞清楚 JWT 内部结构后面出了问题根本无从排查。一个 JWT 长这样eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMTAwMSIsInVpZCI6MTAwMSwiZXhwIjoxNzM1NjAwMDAwfQ.8fQZfUa-vQmWJXpJQjwrQN7x8VdzJxbrD1X8nJvYlFw整串 token 由两个英文句点分成三段Header、Payload、Signature。每一段都经过 Base64URL 编码注意这里是 URL-safe 的 Base64 变体不是普通 Base64区别在于它把换成-、把/换成_同时去掉末尾的填充符因为和/放在 URL 或请求头里容易被转义或误解。2.1 Header、Payload、Signature 的编码细节先看第一段 Header。它里面主要声明了两样东西签名算法和令牌类型。一个典型的 Header 等于是下面这个 JSON 做 Base64URL 编码后的结果{alg:HS256,typ:JWT}alg告诉服务端这个 token 是用什么算法签名的typ则声明了这是一个 JWT。后续服务端验签时第一步就是读这个 Header所以校验代码里一定要手动指定允许的算法集合不能完全信任 Header 里传的算法否则可能有算法混淆攻击的风险这一点后面踩坑章节我会展开说。第二段是 Payload也就是载荷部分存放认证相关的声明信息。JWT 里定义了一些标准的注册声明比如sub主题一般是用户标识、exp过期时间Unix 时间戳、iat签发时间、jti令牌唯一标识等等。除了标准声明你也可以往里面放自定义字段比如用户 ID、角色、权限列表。前面那个示例 token 的 Payload 解码后大概是{sub:user1001,uid:1001,exp:1735600000}第三段是 Signature签名部分。签名的作用是保证前面两段的内容没有被篡改。具体的生成过程是把Base64URL(Header) . Base64URL(Payload)这个字符串配合密钥再用 Header 里声明的签名算法计算出来。如果中间有人把 Payload 里的用户权限从普通用户改成管理员那么验签时重新计算的签名就会和原签名对不上服务端直接拒绝非常简洁有效。2.2 签名是怎么算出来的为什么能防篡改HS256 是目前最常用的对称签名算法逻辑很好理解。它的计算过程就一行概念公式signature HMAC_SHA256(base64Url(header) . base64Url(payload), secretKey)把前两段拼接之后的字符串和密钥一起丢进 HMAC-SHA256 算法得到的输出再做 Base64URL 编码就是第三段签名。验签的时候服务端用同一个密钥把同样的字符串重算一遍签名然后和 token 里携带的签名做比对。只要两边一致就说明 Header 和 Payload 在传输过程中没有被改动过。除了 HS256还有 RSA 系列的 RS256 和椭圆曲线系列的 ES256。RS256 用的是非对称密钥签发方持有私钥验签方只需要公钥。这种模式在微服务架构里特别有用比如网关统一用私钥签发下游各个服务只保存公钥就能验签密钥分发范围小安全性更可控。注意无论你用哪种算法JWT 的防篡改都只针对签名Payload 本身是明文可见的。任何人都能轻松解码出 Header 和 Payload 的内容所以千万不要把密码、身份证号、银行卡号这类敏感信息放进 token 里。2.3 一个最常见的误解Base64 不是加密每次讲到这里都有人把 Base64 当成加密手段。这里特别强调一下Base64 只是一个编码规则它没有任何保密能力。你把 JSON 转成 Base64 字符串之后任何拿到字符串的人都可以反过来解码整个过程和加密没有半点关系。网上大量的在线解码工具把 token 贴进去就能看到三段内容。这本身不是漏洞JWT 的设计目标本来就是在客户端和服务器之间传递签名后的公开数据。但如果你理解偏差了把敏感信息当成反正转成乱码了别人看不懂而塞进去那就等于把密码贴在请求头里到处转发这是非常危险的行为。我见过一个真实的线上事故有个项目把用户的手机号和邮箱明文写进 Payload有一天 token 被某个前端日志平台错误上报了最后所有用户的联系方式都泄漏了出来。教训很简单JWT 的 Payload 里只放不敏感的标识性信息比如用户 ID、昵称、角色一旦需要更多资料服务端拿这些标识去库里查就行。3. Java 端落地三件套签发、拦截、校验接下来讲 Java 里的实际接入。我一直建议不要自己手写 JWT 的编码、解码和签名逻辑成熟的库已经把这些细节处理得很好了你只需要调用 API。市面上比较常用的两个 Java 库是 jjwt 和 java-jwt我这里主要用 jjwt 演示因为它的 API 设计比较直观社区也活跃Spring 项目里集成很顺畅。3.1 依赖选型为什么我建议用现成库而不是自己手写自己实现一个 JWT 的难点不在于编码而在于签名算法实现、安全防护和兼容性处理。HMAC-SHA256 本身虽然不难写但 JWT 规范里还有很多边角细节比如 Base64URL 填充处理、多种签名算法的抽象、异常类型划分、claims 的类型转换这些在一个生产环境里都会变成复杂问题。直接用维护良好的开源库能少踩很多坑。我推荐 jjwt 0.11.5 这个版本它的 API 稳定文档明确配合 Jackson 可以很方便地处理 JSON。Maven 里加三个依赖dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version0.11.5/version scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId version0.11.5/version scoperuntime/scope /dependency注意 jjwt-api 是编译期依赖jjwt-impl 和 jjwt-jackson 是运行时实现这个分层设计可以让你在不改变业务代码的情况下替换底层实现。3.2 签发令牌把用户身份信息写进 claims签发 token 的逻辑放在一个统一的 TokenService 里其他地方只负责调用。这里我给出一个最基础的签名方法用户登录成功后传入用户 ID 和用户名生成一个有效的 HS256 签名 token。Service public class TokenService { private static final String SECRET your-secret-key-please-change-this-in-production-2024; private static final long ACCESS_TOKEN_TTL_MS 30 * 60 * 1000L; // 30 分钟 private Key signingKey() { return Keys.hmacShaKeyFor(SECRET.getBytes(StandardCharsets.UTF_8)); } public String createAccessToken(Long userId, String username) { Date now new Date(); Date expiry new Date(now.getTime() ACCESS_TOKEN_TTL_MS); return Jwts.builder() .setSubject(username) .claim(uid, userId) .setIssuedAt(now) .setExpiration(expiry) .signWith(signingKey(), SignatureAlgorithm.HS256) .compact(); } }几个容易忽略的点说一下。密钥长度必须满足 HMAC-SHA256 的最小要求太短会报错所以生产环境里我一般用环境变量注入密钥。过期时间的单位是毫秒上面的 30 分钟是我在内部管理系统里常用的值对外部用户系统建议更短。claim可以放多个自定义字段但就像前面说的只放非敏感信息。不过这里有个工程规范问题这段代码里密钥是硬编码的只适合本地测试。生产环境一定要把密钥抽到环境变量或配置中心代码仓库里不能出现真实密钥。到第 5 章我会专门讲密钥管理策略。3.3 拦截并校验过滤器怎么接进 Spring Boot签发完 token接下来就是对受保护接口做拦截校验。Spring Boot 里最常见的做法是定义一个过滤器实现OncePerRequestFilter保证每个请求只经过一次校验逻辑。这个过滤器从Authorization请求头里取 token验签通过后把用户信息放到 request 属性里后面的业务代码可以直接取用。Component public class JwtAuthFilter extends OncePerRequestFilter { private final TokenService tokenService; public JwtAuthFilter(TokenService tokenService) { this.tokenService tokenService; } Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String uri request.getRequestURI(); if (uri.startsWith(/auth/login) || uri.startsWith(/auth/refresh)) { chain.doFilter(request, response); return; } String header request.getHeader(Authorization); if (header null || !header.startsWith(Bearer )) { writeUnauthorized(response, missing token); return; } String token header.substring(7); try { Claims claims tokenService.parseToken(token); request.setAttribute(uid, claims.get(uid, Long.class)); request.setAttribute(username, claims.getSubject()); chain.doFilter(request, response); } catch (ExpiredJwtException e) { writeUnauthorized(response, token expired); } catch (JwtException | IllegalArgumentException e) { writeUnauthorized(response, token invalid); } } }这里有两个设计思路要特别说明。一是 token 的传递约定业界通用的做法是在请求头里用Bearer前缀标识过滤器解析时去掉前缀只保留 token 本身。不要自己发明 header 名字也不要支持多个头里塞 token 的方式统一一种就够。二是白名单路径的判断登录接口、刷新 token 接口这类自己就应该在拦截前放行如果项目里用了 Spring Security放行名单可以在 SecurityFilterChain 里统一配置比在过滤器里挨个判断路径更清晰。TokenService 里对应补一个解析方法public Claims parseToken(String token) { return Jwts.parserBuilder() .setSigningKey(signingKey()) .build() .parseClaimsJws(token) .getBody(); }parseClaimsJws方法内部会自动做签名验证和一个完整的格式检查签名不对直接抛JwtException过期了抛ExpiredJwtException。我一直觉得 jjwt 的异常设计很贴心它能让我们在过滤器里判断出 token 到底是过期了还是被篡改了然后返回不同的提示信息给前端方便前端决定是跳登录页还是去刷新 token。3.4 统一异常返回别让前端拿到丑陋的 401 页面很多新手项目在过滤器里拦截失败后直接回一个 401 状态码响应体里什么都没有。前端拿到状态码倒是能判断认证失败但调试时看不到任何提示体验很差。更规范的做法是像上面代码里那样统一写一个 JSON 响应体里面带上业务错误码和错误描述。private void writeUnauthorized(HttpServletResponse response, String message) throws IOException { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType(application/json;charsetUTF-8); response.getWriter().write( {\code\:401,\msg\:\ message \} ); }如果项目里有全局异常处理器也可以把过滤器里的异常包装后交给全局处理器统一输出这样错误码格式和层级都是可控的。我建议在项目初期就把错误码规范定下来比如 40101 表示 token 缺失、40102 表示 token 过期、40103 表示签名验证失败前端可以根据不同错误码走不同的交互逻辑后期维护起来会很舒服。4. 接入 JWT 后最容易踩的坑以及对应解法我前面说的都是正常流程但 JWT 真正让团队头疼的地方往往是在接入之后。下面这几个坑全部来自我实际见过或处理过的线上问题每一个都值得重视。4.1 密钥硬编码和算法混淆攻击第一个坑是密钥问题。有些项目为了省事直接把密钥写死在代码里甚至提交到 Git 仓库这是非常危险的。代码仓库一旦泄漏攻击者拿到密钥就能自己签发任意用户的 token等于整个认证体系直接报废。我见过一个更隐蔽的场景有一次做安全测试发现一个接口居然接受algnone的 token也就是说攻击者把 Header 里的算法改成 none然后手动构造一个 Payload不签名就直接发过来服务端竟然验证通过了。这是因为校验代码没有显式指定允许的算法而是完全信任了 Header 里的声明。对应的解法有两个方面。第一密钥必须从代码里抽离用环境变量、配置中心或者密管服务管理第二校验时必须指定签名算法不要盲目信任 Header 里的alg字段。在 jjwt 0.11 里我一般先指定算法再用对应的 Builder 创建解析器避免默认行为带来的歧义。4.2 过期时间拍脑袋要么频繁踢下线要么长期有效第二个坑是过期时间设置不合理。有过把 token 有效期设成几分钟的用户用着用着就掉线一天能收到十几个投诉也有设成整整一年的结果离职员工的 token 成了永久后门。我的建议是分角色、分场景设置。普通用户系统的 access token 我给 15 分钟到 2 小时配合 refresh token 实现无感续期内部管理后台可以放宽到 4 小时操作敏感的接口比如支付、修改密码单独在前端要求二次确认或者额外校验。token 有效期设太短用户体验会变差但可以通过刷新机制弥补设太长安全风险又会指数上升。核心原则是能用刷新机制解决的体验问题不要用延长 token 有效期来解决。4.3 注销与踢人无状态令牌没法服务端失效聊到 JWT 一定会有人问用户点了退出登录token 还能继续用怎么办确实JWT 无状态意味着服务端没有集中的会话记录签出去的 token 只要没过期理论上就一直有效。Session 方案里删掉 Session 就能强制下线这一点是 JWT 的天然短板。实际项目里我一般用两种方案处理。第一种是黑名单方案用户注销时把该 token 的jtiToken 唯一标识和剩余有效期写进 Redis后续请求如果发现 token 的jti在黑名单里就直接拒绝。这个方案简单有效代价是多一次 Redis 查询。第二种是白名单方案签发 token 时在 Redis 里存一个userId - token的映射只有映射里匹配的 token 才有效踢人时直接删掉对应 key所有旧 token 全部失效。白名单本质上让 token 退化成有状态了适合对登出时效要求很高的系统但在无状态这个核心优势上打了折扣。具体选哪个还是看业务需求。普通互联网应用我推荐黑名单简单又快后台管理系统建议白名单权限回收比较彻底。4.4 并发刷新场景下的 Token 轮换冲突第三个坑是关于 refresh token 的并发刷新。刷新逻辑做得简单了会出现一个 bug用户同时在两个终端使用或者网络抖动导致刷新请求重复发送结果两个刷新请求都成功旧的 refresh token 还在两侧同时被标记为无效用户被莫名其妙踢下线。解决思路是给 refresh token 增加轮换机制和唯一性约束。每次刷新时不仅签发新的 access token还要签发新的 refresh token旧的 refresh token 立即作废。签发时携带随机生成的jti刷新时用 SQL 的唯一索引或者 Redis 的 setnx 命令保证同一时刻只有一个刷新请求能生效其他请求返回一个明确错误让前端重新走登录流程。4.5 服务器时间不一致导致提前过期第四个坑来自基础设施。JWT 的过期校验依赖服务器当前时间如果各服务部署的机器时间不同步经常会出现一种诡异现象token 明明没过期请求发给 A 服务能用发给 B 服务却提示过期。尤其是一些自建的物理机环境NTP 没有配置好机器时间可能差出几分钟甚至更多。这个问题的根治方案是保证所有服务器时间同步配置 NTP 服务是运维的必修课。但为了保险在验签过期判断时可以留一个很小的时钟偏移窗口比如允许 30 秒以内的偏差public boolean isExpired(Claims claims) { Date expiration claims.getExpiration(); long skew 30 * 1000L; // 30 秒容忍窗口 return System.currentTimeMillis() expiration.getTime() skew; }注意这个容忍窗口不能开太大一般不超过 60 秒否则 token 实际有效期限被变相延长安全上有风险。4.6 日志里打 Token、PII 信息泄漏JWT 接入后很常见的一个失误是日志打得太随意。很多框架的访问日志会默认打印整个请求头而 token 就在Authorization头里被打进日志之后一旦日志系统被拖库或者权限失控所有用户的令牌就全泄漏了。我在项目里会做两层防护第一层是日志配置里过滤Authorization请求头不打印令牌内容第二层是统一封装用户信息打印方法只输出脱敏后的用户 ID不输出手机号、邮箱、身份证等个人信息。这个看起来和核心认证功能无关但真的出事的时候它就是最后一道防线。日志里凡是出现 token 的地方都要打上脱敏的标记。4.7 请求头过大与 Payload 臃肿最后一个坑不是安全性的是性能层面的。有人喜欢把所有用户信息都塞进 claims头像 URL、昵称、地址、权限列表几十个字段一起放。这样 token 会非常大而 HTTP 请求头是有大小限制的常见的服务器默认限制在 8KB 左右。一旦 token 超过限制请求直接报错排查起来还很费劲。而且 token 变大之后每个请求都要携带更大的请求头带宽和延迟都会受到影响在高并发场景下这个开销会被放大。我的建议是 claims 里只放用户 ID 和必要的基础字段其他数据都靠用户 ID 去查缓存或数据库。权限信息如果多可以拆成独立的权限服务不要全塞进 token。5. 更进一步的工程化刷新令牌、密钥管理与多服务场景基础版的 JWT 接入能解决大部分需求但真实项目里还需要一套更完整的工程方案。这里我围绕刷新令牌、密钥管理和多服务架构这三个方向给你一套可以直接落地的设计。5.1 刷新令牌的标准姿势access token 的过期时间短用户不可能每隔几十分钟就重新登录一次所以需要引入 refresh token 来实现无感续期。refresh token 的生命周期比 access token 长得多一般 7 天到 30 天并且只通过一个单独的刷新接口来换取新的 access token不参与业务接口的认证。刷新流程大致是这样登录成功后服务端同时签发 access token 和 refresh token业务接口只认 access token过期后前端用 refresh token 调用/auth/refresh刷新接口校验 refresh token 有效后签发新的 access token 给前端如果 refresh token 也过期了前端引导用户重新登录。为什么要把 refresh token 单独拿出来而不是干脆把 access token 有效期设长一点因为这会带来一个权衡业务接口频繁验证 token一旦 token 泄漏攻击者能使用的时间窗口就取决于 access token 的有效期。有效期短泄漏造成的损失小但用户体验差有了 refresh token既能把 access token 的有效期控制在分钟级又不会逼着用户频繁登录万一 refresh token 泄漏它的使用路径只有刷新接口安全控制可以做得更严比如检测到异地刷新时直接要求重新认证。数据库里管理 refresh token 的表可以这样设计重点是保存 token 的 hash 值和过期时间CREATE TABLE refresh_token ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, token_hash VARCHAR(64) NOT NULL, expires_at DATETIME NOT NULL, created_at DATETIME NOT NULL, revoked TINYINT NOT NULL DEFAULT 0, UNIQUE KEY uk_token_hash (token_hash) );存储 refresh token 时建议只存哈希值不要存原文。这样即使数据库被拖走攻击者也无法直接拿里面的值去调用刷新接口。整个刷新令牌体系做完之后用户的登录体验会显得非常无感这个投入很值得。5.2 密钥管理与轮换密钥管理的话题前面已经提过好几次这里集中展开。HS256 用的是对称密钥所有需要验签的服务都必须持有同一个密钥密钥的分发范围越大泄漏风险越高。所以我给团队定过一个原则单体应用用 HS256 没问题密钥统一走环境变量一旦服务拆成多个微服务而且数量超过两三个优先考虑 RS256。RS256 是非对称算法只有签发方持有私钥验签方只有公钥。我的建议是私钥只放在统一的认证服务中心或网关里各业务服务只保存公钥这样私钥暴露面非常小。公钥本身不敏感即使泄漏了也只能验签不能签发危害要小得多。密钥轮换也是一个必须提前考虑的问题。简单说就是不能一把密钥用到天荒地老需要定期更换。轮换时不能直接换掉就完事因为旧 token 在切换之后全部失效用户会同时掉线。标准做法是在切换密钥时保留一段时间的双密钥并行期新签发的 token 用新密钥校验的时候新旧密钥都允许通过等旧 token 基本过期后再彻底下线旧密钥。整个过程可以用一个配置文件或者配置中心的密钥版本列表来控制。5.3 在多微服务与网关场景下的认证策略最后聊一下多服务架构下的认证策略。JWT 在微服务里的核心价值是认证一次处处验证。用户只需要在网关处过一遍认证网关把 token 验签通过后把用户信息以请求头的方式向下游服务传递比如X-User-Id、X-User-Role。下游服务不再需要关心 token 本身直接信任网关传过来的请求头就行。这个模式有一个前提必须注意下游服务要默认拒绝来自外部的X-User-Id这类请求头。如果网关外面的人随便拼一个X-User-Id: 123就能伪装管理员那整个体系就形同虚设。解决方法是让下游服务只信任网关的请求头内部网络通过服务间白名单或者专用网关转发来保证不允许外部请求直接打到下游服务。在实现上网关的验签过滤器逻辑和我们第 3 章写的过滤器基本一致只是把解析出来的用户信息从 request attribute 改成写入转发给下游的 header同时校验通过后要把下游通常会检查的白名单规则同步维护好。这样每个微服务不需要自己集成 JWT 库各自只依赖运维侧约定的内部请求头代码侵入非常小。我个人在实际项目里最顺手的组合是网关层集中验签access token 设 30 分钟有效期refresh token 集中管理且支持轮换Redis 里放必要的黑名单用于用户注销和踢人。这一套组合不复杂但把常见的安全坑基本都堵住了。如果你是第一次接入 JWT 的项目直接从第 3 章的过滤器版本起步完全够用关键是把签名校验、过期时间和密钥管理这三件事在一开始就做对后面的工程化扩展就不会太难。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑