在对使用JWT与Access Token和Refresh Token进行身份验证进行了一些研究之后。我是这样理解的。
- 登录后,返回用户访问令牌和刷新令牌(两者使用相同的JWT技术)
- 在数据库中保存刷新令牌(一个用户可以为多个设备拥有多个刷新令牌)
- 每当用户发送具有无效访问令牌的请求时,请选中Refresh Token并调用另一个api以获取新的访问令牌(在客户端执行此操作)。之后,调用api,使用新的访问令牌再次获取数据
- 如果刷新令牌无效,则删除其在数据库中的记录,用户必须重新登录才能获得新的刷新令牌
我是否正确理解访问和刷新令牌技术?请给我一些建议。提前感谢。
在您列出的4个步骤中,有些看起来或多或少是正确的,而另一些则不然。我将首先给出刷新令牌创建的前提以及它们的主要目的。
使用只带有访问令牌的JWT模式,当JWT令牌过期时,可能会出现可用性问题。以银行网站为例。当用户登录时,他会收到一个具有特定到期日的JWT令牌(通常存储在令牌的声明部分的exp
密钥下)。如果代币的有效期为5分钟,那么从可用性的角度来看,这意味着网站必须强制用户每5分钟手动登录一次。显然,这不是最好的用户体验,因为这意味着当令牌过期时,恰好处于某个业务流程中间的用户可能会失去所有工作。这就是刷新令牌来缓解这个问题的地方。
使用带有刷新令牌的JWT模式意味着用户同时接收访问和刷新令牌。这里的典型工作流程可能是:
- 登录后,返回用户访问令牌和刷新令牌(两者使用相同的JWT技术)。接收器记录访问令牌何时设置为过期(例如15分钟)
- 随着访问令牌到期的临近(例如10分钟),UI将向后端发送刷新令牌,以获得新的访问令牌(和刷新令牌)。这可以明确地完成,例如在显示弹出窗口询问用户是否想继续的网站上。或者可以在隐藏模式下进行,在引擎盖下进行REST调用以获取新的访问令牌
- 对于无法使用刷新令牌来获得新访问令牌的边缘情况,则需要身份验证的下一个用户操作将失败。在这种情况下,用户将不得不重定向到登录页面。但是,由于这种情况通常很少见,因此不会取消刷新令牌模式的资格
我还指出,在数据库中存储访问/刷新令牌在很大程度上违背了JWT模式的目的。使用JWT的一个主要原因是它将用户会话状态从应用程序推送到用户身上。通过在数据库中存储令牌,您完全可以让用户会话非常有状态,这有各种潜在的缺点。考虑使用上面建议的工作流来避免这样做。
在我看来,刷新令牌需要存储并与设备和用户关联。
示例:用户登录设备A
- 呼叫登录端点
- 验证用户是否有效
- 如果有效,则生成与userid&装置id
- 将所需数据存储到表或存储引擎(user_sessions..等)user_id | device_id | refresh_token | expires_at
- 返回access_token、refresh_token和access_token_expires_at的有效负载
- 前端,存储有效载荷
- 使用资源时,请检查以下内容
- 如果refresh_token_expires_at>现在,将它们注销,显示您的会话超时(或者您可以有一个从未过期的refresh_token…例如,refresh_take_expires_at可以为0)
- 如果access_toke_expires_at>现在,将刷新令牌端点与负载一起调用
- 在刷新端点上,验证调用并根据存储的数据检查刷新令牌。
- 如果刷新令牌对此用户+设备有效,则生成新的access_token
- 返回access_token及其expires_at
- 如果刷新令牌为INvalid,则返回INvalid
- 前端将用户注销
**在任何情况下,如果刷新令牌被破坏,它将只针对特定的设备/用户。然后,用户可以停用该设备或从其列表中删除该设备。此操作将使refresh_token在下次刷新调用时失效。