当前位置:首页 > Java技术 > 正文内容

Token快过期了怎么办?三种续期方案,我选Refresh Token!

canca2周前 (09-23)Java技术18

同学,我们系统用的是Token认证,用户反馈说经常需要重新登录,体验很差。你有什么好的续期方案吗?顺便说说Token该怎么选型?

上面这段对话,是不是感觉下一秒就会发生在你的面试中?

别怕,这其实是一道“送分题”。它不仅考验你对用户认证体系的理解深度,更能体现你对系统设计中安全性用户体验这对“欢喜冤家”的平衡能力。

今天,我们就把Token续期和选型这点事,一次性讲得明明白白。

一、为什么需要续期?不让Token永不过期不就行了?

在回答“怎么办”之前,我们必须先弄清楚“为什么”。

把Token设置成永不过期?听起来似乎一劳永逸,但这是一个极其危险的想法。Token本质上是一张进入你家小区的“临时门禁卡”,如果这张卡永不失效,一旦丢失(被黑客窃取),后果不堪设想。

1.png

所以,Token必须有有效期!

但有效期太短,用户正用得爽呢,突然就被强制下线,要求重新登录,那体验简直是灾难。为了解决这个矛盾,“续期”机制应运而生。它的核心目标是:在保障安全的前提下,让用户感觉不到Token的存在,实现“无感”续期。

二、续期三大主流方案,你Pick哪一个?

目前业界主流的续期方案有三种,我们逐一分析。

方案一:滑动窗口续期 (Sliding Session)

这是一种“在你无知无觉中,就帮你把事办了”的方案。

工作方式

系统为每个Token设置一个过期时间(比如30分钟)。当用户带着Token来访问时,如果Token有效,服务端在返回数据的同时,会自动给用户换发一个拥有新的30分钟过期时间的新Token。

2.png

  • 优点

    实现简单,逻辑清晰,只要用户在规定时间内持续活跃,就能一直在线。

  • 缺点

    1. 安全风险

      如果一个Token被盗,攻击者也可以通过高频访问来让这个Token“永生”。
    2. 并发问题

      如果用户同时发了多个请求,可能会瞬间收到好几个新Token,客户端会感到困惑:“我到底该用哪一个?”
    3. IO压力

      对于需要将Token信息存储在服务端的普通Token(下文会讲),每次续期都意味着一次写操作,会增加服务端IO压力。


方案二:刷新令牌机制 (Refresh Token) - ⭐⭐⭐⭐⭐(强烈推荐)

这是目前最主流、最安全、最推荐的方案,也是你面试时最应该拿出来详谈的方案。

核心逻辑:双令牌解耦(Access Token=访问权,Refresh Token=续期权)

它引入了“双令牌”的概念,把“访问权限”和“续期权限”解耦。

工作方式

  1. 首次登录

    用户登录成功,服务器返回两个Token: 

    Access Token

    访问令牌,生命周期很短(如1小时),用于API请求时的身份验证。

    Refresh Token

    刷新令牌,生命周期很长(如7天),专门用来获取新的Access Token
  2. 日常访问
    客户端每次请求API,都只带上Access Token
  3. Access Token过期

    Access Token过期,服务器返回401 Unauthorized

  4. 静默刷新

    客户端的请求拦截器捕获到401后,自动携带Refresh Token去请求一个专门的刷新接口(如/refresh)。

  5. 获取新生

    服务器验证Refresh Token有效后,签发一个全新的Access Token,返回给客户端。

  6. 无感重试

    客户端拿到新的Access Token后,重新执行刚才失败的API请求。整个过程对用户完全透明。

3.png

优点

  • 极致安全

    Access Token寿命极短,即使泄露,攻击者也只能猖獗一小会儿。而用于续命的Refresh Token只在刷新时才露面,且服务端可以将其加入黑名单,强制某些用户下线。

  • 体验与控制兼备

    完美解决了用户体验与服务端控制权的平衡问题。

方案三:服务端自动续期

这是一种“爱操心”的服务端策略。

  • 工作方式

    客户端正常请求,服务端在验证Token的同时,会检查其剩余有效期。如果发现有效期不足某个阈值(比如只剩5分钟了),就在这次请求的响应头里,主动塞一个新的Token给客户端。客户端需要检查响应头,如果发现有新Token,就替换掉本地的旧Token。

4.png


  • 优点

    续期时机由服务端掌握,客户端逻辑相对简单。

  • 缺点

    属于“被动”续期,如果用户在Token即将过期的几分钟内恰好没有任何操作,那么Token还是会过期。此外,每次响应都可能需要额外的数据传输。

三、灵魂拷问:JWT还是普通Token,到底该怎么选?

聊完了续期,我们必须面对另一个核心问题:你手里的Token,到底是什么类型的?这直接决定了你的系统架构。

特性维度

JWT (JSON Web Token) - “身份证”

普通 Token - “储物柜钥匙”

核心机制

无状态 (Stateless)
Token自身包含所有用户信息,服务端无需保存。

有状态 (Stateful)
Token只是一个引用ID,用户信息存在于服务端(如Redis)。

性能/扩展性


服务端验证签名即可,无需查库/缓存


每次请求都需查询一次DB/缓存,有I/O开销。

安全性

⚠️
Payload部分是明文,严禁存放敏感信息


Token本身无任何意义,信息不外泄。

吊销/注销


过期前始终有效。想让其提前失效,需引入黑名单。


只需从Redis中删除Token记录,即可立即失效。

微服务

极佳
天然适合微服务。任何服务只要有密钥,就能独立验证。


所有服务都需访问同一个中心化的会话存储,增加耦合。

选型结论:

  • 单体应用 & 强管理需求

    如果你的系统是传统的单体应用,或者需要频繁地进行“强制用户下线”、“后台踢人”等强力管控操作,那么普通Token(配合Redis)是你的不二之选。它的控制力无与伦比。

  • 微服务架构 & 无状态API

    如果你的系统是微服务架构,或者追求无状态、可无限水平扩展的API,那么请果断拥抱JWT。它为解耦而生。

四、最佳实践:Refresh Token + JWT

看到这里,你可能会想,有没有一种方案能集各家之所长?

当然有!那就是 Refresh Token机制 + JWT 的黄金组合。

5.png

这套组合拳的打法是:

  1. Access Token 使用JWT格式

    充分利用JWT的无状态、适合微服务的特性。同时,将其生命周期设置得极短(比如15分钟到1小时),即使泄露,风险也极低。

  2. Refresh Token 使用普通Token格式

    它只是一个无意义的随机字符串,存储在服务端(比如Redis或数据库中),并与用户ID关联。这样服务端就拥有了对续期权限的绝对控制,可以随时让某个Refresh Token失效。

这个组合,既享受了JWT在业务请求中的高性能,又通过Refresh Token弥补了JWT难以吊销的短板,同时保证了优秀的用户体验。堪称完美!

6.png

总结

回到开头的面试题,现在你可以自信地给出答案了:

  1. 阐述续期的必要性

    平衡安全与体验。

  2. 列举三种续期方案

    滑动窗口、Refresh Token(重点讲解)、服务端自动续期。表明你对Refresh Token方案的青睐,并详细阐述其“双令牌”工作流程和优势。

  3. 分析Token选型

    清晰对比JWT和普通Token的优劣,并给出在单体应用和微服务架构下的选型建议。

  4. 给出最佳实践

    抛出Refresh Token + JWT的黄金组合,并解释它如何取长补短,成为现代应用的事实标准。

搞懂了这些,下次面试官再问起Token,你就可以把这篇文章的要点娓娓道来。相信我,这绝对会成为你面试中的高光时刻。


扫描二维码推送至手机访问。

版权声明:本文由Ant.Master's Blog发布,如需转载请注明出处。

本文链接:https://iant.work/post/897.html

分享给朋友:
返回列表

上一篇:ThreadLocal跨线程问题

没有最新的文章了...

“Token快过期了怎么办?三种续期方案,我选Refresh Token!” 的相关文章

对象序列化与反序列化

    序列化,并不是JAVA独有的。因此,在这里我用比较通俗的话说了。序列化就是把一个对象转换成有规则的二进制流。而反序列化就是把有规则的二进制数据重整成一个对象。其好处不难看见:1.可以把一个对象保存在一个文件里。例如,下载软件。当您关闭了软件,下次再打开...

Socket与ServerSocket的问题

//服务器端:import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.ServerSock...

JSP与Servlet的对应关系

以前在QQzone写下的文章现在贴到这里来了... 最近比较忙啊!现在抽身写一篇文章。是关于JSP与Servlet的对应关系的。希望对大家有所帮助。其实我也是刚刚学的......-------Servlet--------------JSP----------1.ServletContext&nbs...

JAVA获得一个文件夹大小

在JAVA里没有现成的方法获取一个文件夹的大小,那么我们可以用递归的方法,获取文件夹的大小。    import  java.util.*;  import  java.io.*;  class  GetFileSi...

JAVA内部类终极实例

最近心情不好,不想说太多东西了!电脑坏了,我现在又病了. class ClassFactory{ private final static String userName = "Hello,My name is CAnca."; public static Thread in =...

字符,字节和编码

字符,字节和编码

转自:http://www.regexlab.com/zh/encoding.htm------------------------------------------------------------- 级别:中级 摘要:本文介绍了字符与编码的发展过程,相关概念的正确理解。举例说明了一些实际应...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。