从概念上讲,我非常喜欢JWT,因为它符合REST等无状态(没有状态保存服务器端,所有相关数据都包含在令牌中) .
我不确定的是:如果没有连接(例如,“记住我”功能),你将如何处理令牌到期?
网络上有一个新兴的JWT报道,但我找不到任何回答过期问题的人 .
Clarification: 我不是问如何处理令牌即将到期,但是当令牌已经过期时(用户关闭网站/应用程序一段时间)该怎么做 . 我想到的最简单的解决方案是缓存用户的凭据,这是相当不安全的 .
我想你要问的是如何使JWT服务器端无效的长期令牌(例如“记住我”功能)?
我最近自己遇到了这个问题,并最终使用唯一的用户密码来使令牌无效,当用户尝试验证使用旧秘密生成的令牌时,它将失败 . 用户名可以在解码的JWT预验证中找到 .
您甚至可以使用用户密码salt,这样当用户更改密码时,任何当前的JWT都会失效(假设您同时更改了盐),这可能会有问题,但密码哈希和JWT是会变得紧密耦合
如果我遵循,我不太确定,但我会写出我的想法 .
想象一下令牌作为酒店卡,您提前支付5天(记住我将在5天后到期) . 我可以在5天内进入建筑物,车库,房间等,在这5天之后,它将不再起作用 .
令牌已经过期时该怎么办?什么都没有 .
想象一下,我支付了5天的费用,我有一个紧迫感,我回家了(口袋里的卡片) . 酒店根本不关心,当5天过去时,卡片只是一块无用的塑料,如果你试图在酒店使用,它什么都不做 .
所以回到web开发 . 如果您提供记住我的服务,您可以设置一个有效期,比如7天 . 只要用户拥有令牌,他就可以毫无问题地访问服务 . 如果他丢失了令牌,他需要再次登录 . 如果他使用令牌并且已经过期,他也需要再次登录 .
如果他登录,他会获得一个令牌7天,如果他不再使用它,20天后他又来了,他需要再次登录,服务器将拒绝你的请愿,直到你这样做 .
如果你在前端使用像角度这样的东西,我会做的是在启动时检查令牌验证,这样你就可以获得良好的用户体验 .
我不明白你的问题是de caching的事情 .
您需要在客户端上保留JWT,以便在页面加载时可用,最安全的策略是仅使用HTTPS的cookie . 这将在每次请求时将JWT发送到您的服务器,服务器可以检查令牌的有效性并在它过期时拒绝它 . 您如何处理到期时间取决于您拥有的Web应用程序的类型 .
对于单页面应用程序(例如Angular.js应用程序),您可能希望构建应用程序,以便在引导应用程序的其余部分之前向服务器发出初始请求 . 如果服务器发现此请求中的JWT已过期,则会发出401响应 . 您的应用程序将通过呈现登录表单来响应此响应 . 否则,它将继续假设JWT有效并可用于访问所需资源 . 如果应用程序在任何时候看到401,它应该将用户带回登录表单 .
对于在服务器上呈现其页面的传统Web应用程序:对于任何具有过期JWT的请求(从cookie中读取),服务器应发出302重定向到登录表单 .
我可以想到一种方法,但它并没有真正定义标准 .
如何为索赔添加另一种具有不同寿命的到期日期呢?对于两个声明,我们可以将其中较短的一个视为资源访问到期日期,将较长的一个视为刷新到期日期,例如:
{ "iat": /* current time */, "bbf": /* current time + 1 hour -- expired means no resource access */ "exp": /* current time + 1 week -- expired means cannot refresh */ }
(注意:我使用 bbf 表示较短的截止日期 . 没有具体原因,只是因为它的长度为3个字符 . )
bbf
因此,在“记住我”的情况下,当用户重新连接时,他可以使用相同的令牌来请求新的令牌,但不能访问该资源 . 这样,包含了所有相关数据在令牌内 - 不需要额外的令牌 .
最后,当"remember me"未选中时,只需对 bbf 和 exp 使用相同的生命周期 .
exp
除了@Jesus answer之外,您还可以考虑实施刷新令牌系统:https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
在酒店示例中,您的酒店卡(访问令牌)在时间X之后将无效,但在接待处您可以使用您的护照(刷新令牌)再次获得新的酒店卡 .
您可以使用有关用户正在使用的设备的其他数据将刷新令牌存储在数据库中,从而允许他在设备被盗时禁用该设备 .
例:
首先正确的客户端登录:创建一个永久有效的刷新令牌(直到它被删除或失效)
在数据库中存储刷新令牌具有到客户端的到期时间的
返回访问令牌(JWT)(此令牌未存储在数据库中)
对于下一个请求,客户端发送访问令牌
现在检查访问令牌是否已过期:
5.1访问令牌未过期,一切正常
5.2访问令牌已过期,检查数据库中是否有刷新令牌
5.2.1刷新令牌在数据库中,返回新的访问令牌
5.2.2数据库中没有刷新令牌,返回401 /注销,用户必须再次登录
希望这可以帮助 .
5 回答
我想你要问的是如何使JWT服务器端无效的长期令牌(例如“记住我”功能)?
我最近自己遇到了这个问题,并最终使用唯一的用户密码来使令牌无效,当用户尝试验证使用旧秘密生成的令牌时,它将失败 . 用户名可以在解码的JWT预验证中找到 .
您甚至可以使用用户密码salt,这样当用户更改密码时,任何当前的JWT都会失效(假设您同时更改了盐),这可能会有问题,但密码哈希和JWT是会变得紧密耦合
如果我遵循,我不太确定,但我会写出我的想法 .
想象一下令牌作为酒店卡,您提前支付5天(记住我将在5天后到期) . 我可以在5天内进入建筑物,车库,房间等,在这5天之后,它将不再起作用 .
令牌已经过期时该怎么办?什么都没有 .
想象一下,我支付了5天的费用,我有一个紧迫感,我回家了(口袋里的卡片) . 酒店根本不关心,当5天过去时,卡片只是一块无用的塑料,如果你试图在酒店使用,它什么都不做 .
所以回到web开发 . 如果您提供记住我的服务,您可以设置一个有效期,比如7天 . 只要用户拥有令牌,他就可以毫无问题地访问服务 . 如果他丢失了令牌,他需要再次登录 . 如果他使用令牌并且已经过期,他也需要再次登录 .
如果他登录,他会获得一个令牌7天,如果他不再使用它,20天后他又来了,他需要再次登录,服务器将拒绝你的请愿,直到你这样做 .
如果你在前端使用像角度这样的东西,我会做的是在启动时检查令牌验证,这样你就可以获得良好的用户体验 .
我不明白你的问题是de caching的事情 .
您需要在客户端上保留JWT,以便在页面加载时可用,最安全的策略是仅使用HTTPS的cookie . 这将在每次请求时将JWT发送到您的服务器,服务器可以检查令牌的有效性并在它过期时拒绝它 . 您如何处理到期时间取决于您拥有的Web应用程序的类型 .
对于单页面应用程序(例如Angular.js应用程序),您可能希望构建应用程序,以便在引导应用程序的其余部分之前向服务器发出初始请求 . 如果服务器发现此请求中的JWT已过期,则会发出401响应 . 您的应用程序将通过呈现登录表单来响应此响应 . 否则,它将继续假设JWT有效并可用于访问所需资源 . 如果应用程序在任何时候看到401,它应该将用户带回登录表单 .
对于在服务器上呈现其页面的传统Web应用程序:对于任何具有过期JWT的请求(从cookie中读取),服务器应发出302重定向到登录表单 .
我可以想到一种方法,但它并没有真正定义标准 .
如何为索赔添加另一种具有不同寿命的到期日期呢?对于两个声明,我们可以将其中较短的一个视为资源访问到期日期,将较长的一个视为刷新到期日期,例如:
(注意:我使用
bbf
表示较短的截止日期 . 没有具体原因,只是因为它的长度为3个字符 . )因此,在“记住我”的情况下,当用户重新连接时,他可以使用相同的令牌来请求新的令牌,但不能访问该资源 . 这样,包含了所有相关数据在令牌内 - 不需要额外的令牌 .
最后,当"remember me"未选中时,只需对
bbf
和exp
使用相同的生命周期 .除了@Jesus answer之外,您还可以考虑实施刷新令牌系统:https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
在酒店示例中,您的酒店卡(访问令牌)在时间X之后将无效,但在接待处您可以使用您的护照(刷新令牌)再次获得新的酒店卡 .
您可以使用有关用户正在使用的设备的其他数据将刷新令牌存储在数据库中,从而允许他在设备被盗时禁用该设备 .
例:
首先正确的客户端登录:创建一个永久有效的刷新令牌(直到它被删除或失效)
在数据库中存储刷新令牌
具有到客户端的到期时间的
返回访问令牌(JWT)(此令牌未存储在数据库中)
对于下一个请求,客户端发送访问令牌
现在检查访问令牌是否已过期:
5.1访问令牌未过期,一切正常
5.2访问令牌已过期,检查数据库中是否有刷新令牌
5.2.1刷新令牌在数据库中,返回新的访问令牌
5.2.2数据库中没有刷新令牌,返回401 /注销,用户必须再次登录
希望这可以帮助 .