使用 JWT 和刷新令牌的 API 身份验证工作流程
大家好,这是我的第一篇帖子,请多多包涵 :P
所以,我希望这篇文章能帮助到所有想要构建身份验证系统的人。我分享的是工作流程,而不是具体的实现方式,这样你可以根据自己的需求进行调整。
我会在文章中穿插一些场景示例,然后逐步讲解服务器端,最后是客户端。我假设你已经有一个注册系统。
情景第一部分
用户已注册。好的,接下来我们需要发送一个 JWT 和一个刷新令牌。服务器会创建它们并发送给用户,用户的浏览器会保存这些令牌,然后我们可爱的小用户就可以在我们的应用中自由探索了。那么,实际发生了什么呢?
服务器端
- 客户已注册
- 为指定用户创建了短期 JWT 和刷新令牌
- 将刷新令牌保存在数据库中,可以是像 Redis 这样的键值数据库。
- 将 JWT 发送回客户端,并将刷新令牌添加到客户端的 Cookie 存储中,并启用 HttpOnly 和 Secure 标志。
您可以在 Node.js 中这样设置 cookie:
response.setHeader('Set-Cookie', 'foo=bar; HttpOnly');
客户端
- 访问服务器注册端点。
- 将 JWT 保存到本地存储。
友情提示:本地存储容易受到跨站脚本攻击 (XSS),请小心 :)
好吧,虽然内容不多。但我们的这份小说明可能会引发一些问题。最具体的问题在于:既然 JWT 存在安全漏洞,为什么我们要将其保存到 localStorage 中呢?
答案
我们将 JWT 保存到客户端本地存储中,因为您可能已经注意到,我们的 JWT 有效期很短,大约只有 30 分钟。这样我们就可以把 JWT 添加到 API 请求的 Authorization 标头中(也就是 bearer 部分)。
然后我们创建了另一个名为刷新令牌的令牌,它可以是任何东西,比如你宠物名字的倒序加上一个计数器,或者一些随机数……什么都可以!我个人比较喜欢用一个叫做“uuid”的Node包。我们将刷新令牌保存到客户端的cookie存储中,并设置了httponly和secure标志。这意味着这个cookie无法被JavaScript访问。而secure标志是关于https的,你应该明白它的作用 :P
这样,当用户访问我们的 API 时,我们的服务器就可以验证用户的 JWT 和刷新令牌。
场景第二部分
用户在我们的应用中永远不会感到无聊!他会不断刷新页面,期待新鲜内容,但猜猜看,我们的小用户发生了什么?30分钟已经过去了!所以您的JWT已过期。现在怎么办?
这次我将用序列图的方式来解释。
客户端
- 用户使用已过期的 JWT 发起 API 请求。
服务器端
- 收到 API 请求,检查 JWT 和刷新令牌。糟糕, JWT 已过期,向客户端发送未授权响应 (401)。
客户端
- 收到来自先前 API 请求的未经授权的响应。
- 点击 API 的刷新端点。
服务器端
- 已收到过期的 JWT,已检查并确认刷新令牌已分配给当前用户。现在刷新 JWT 并将其发送回用户。
客户端
- 已收到 JWT,已将其再次保存到本地存储中。
- 重新执行失败的 API 请求。
- 继续运营。
在 Node.js 的 jsonwebtoken 包中,验证 JWT 时有一个选项:ignoreExpiration。您可以用它来检查令牌是否被修改过。
情景第三部分
我们的用户困了,想登出。但他不是无聊,只是想睡觉而已 :)。他点击了登出按钮。接下来会发生什么?
客户端
- 清除本地存储或直接删除 JWT。
- 发起 API 注销请求。
服务器端
- 收到登出请求。从数据库(类似 Redis 那样 :P)中删除刷新令牌。
- 将刷新令牌 cookie 的过期日期设置为过去的任意日期。
用户已登出。
第一次发这么长的帖子啊?如果帖子可以编辑的话,我可能会添加更多信息 :P。
重要提示:移动端认证方式与此不同。我会在以后的文章中详细介绍。
我们下篇文章再见!
文章来源:https://dev.to/gokayokyay/api-authentication-workflow-with-jwt-and-refresh-tokens-5312