我是否正确理解访问和刷新令牌技术以进行身份​​验证?

问题描述

在对将JWT与访问令牌和刷新令牌一起用于身份验证进行了一些研究之后。我是这样理解的。

  • 登录后,返回到用户访问令牌和刷新令牌(两者使用相同的技术JWT)。
  • 数据库中保存刷新令牌(一个用户可以为多个设备使用多个刷新令牌)。
  • 每当用户发送带有无效访问令牌的请求时,请选中“刷新令牌”并调用一个api以获取新的访问令牌(在客户端执行此操作)。之后,调用api以使用新的访问令牌再次获取数据。
  • 如果“刷新令牌”无效,请删除其在数据库中的记录,并且用户必须再次登录才能获取新的“刷新令牌”。

我是否正确理解访问和刷新令牌技术?请给我一些建议。预先感谢。

解决方法

在您列出的4个步骤中,有些看起来或多或少正确,而另一些则不正确。首先,我将给出创建刷新令牌的原因及其主要目的的前提。

使用仅具有访问令牌的JWT模式,当JWT令牌过期时,存在潜在的可用性问题。以银行网站为例。用户登录时,会收到具有一定期限的JWT令牌(通常存储在令牌的 claims 部分中的import React,{ Component } from 'react' import Person from './Components/Person' class App extends Component { state = { people: [ {name: 'David',age: '30'},{name: 'Michael',age: '27'},{name: 'John',age: '33'} ],bool: true } clickHandler = () => { const currentBool = this.state.bool this.setState({ bool: !currentBool }) } render () { let renderDiv = null if (this.state.bool) { renderDiv = ( <div> {this.state.people.map(person => { return <Person name={person.name} age={person.age} /> })} </div> ) } return ( <div> <button onClick={this.clickHandler}>show/hide</button> {renderDiv} </div> ) } } export default App 键下)。如果给定令牌的有效期为5分钟,那么从可用性的角度来看,这意味着网站将不得不强制用户每5分钟手动登录一次。显然,这不是最佳的用户体验,因为这意味着当令牌过期时恰好处于某个业务流程中间的用户可能会失去所有工作。这是刷新令牌可缓解此问题的地方。

将JWT模式与刷新令牌一起使用意味着用户同时收到访问刷新令牌。一个典型的工作流程可能是:

  • 登录后,返回到用户访问令牌和刷新令牌(两者使用相同的技术JWT)。接收者会记下访问令牌何时设置为过期(例如15分钟)。
  • 随着访问令牌即将到期(例如10分钟),UI会将刷新令牌发送到后端以获取新的访问令牌(和刷新令牌)。这可以明确地完成,例如在显示弹出窗口的网站上询问用户是否要继续。或者可以在隐身模式下完成,在后台进行REST调用以获取新的访问令牌。
  • 对于无法使用刷新令牌来获取新访问令牌的极端情况,则需要身份验证的下一个用户操作将失败。在这种情况下,用户将不得不重定向到登录页面。但是,由于这种情况通常很少见,因此不会取消刷新令牌模式的资格。

我还要指出,将访问/刷新令牌存储在数据库中在很大程度上违反了JWT模式的目的。使用JWT的主要原因之一是,它将用户会话状态从应用程序推送到用户之外。通过将令牌存储在数据库中,您完全可以使用户会话变得非常有状态,这具有各种潜在的缺点。考虑使用上面建议的工作流程来避免这样做。

,

在我看来,您的刷新令牌需要存储并与设备和用户相关联。

示例: 用户登录设备 A

  1. 调用登录端点
  2. 验证用户是否有效
    1. 如果有效,生成与用户 ID 和设备关联的刷新令牌 id
    2. 将所需的数据存储到您的表或存储引擎(user_sessions..etc) 用户 ID | device_id | refresh_token | expires_at
    3. 使用 access_token、refresh_token、access_token_expires_at、refresh_token_expires_at 返回负载
    4. 前端,存储payload
  3. 消耗资源时,请检查以下内容
    1. 如果 refresh_token_expires_at > 现在将它们注销,显示您的会话已超时(或者您可以拥有永不过期的 refresh_token .. 例如 refresh_token_expires_at 可以为 0)
    2. 如果 access_token_expires_at > 现在调用刷新令牌端点和你的负载。
    3. 在刷新端点上,验证调用并根据存储的数据检查刷新令牌。
      1. 如果刷新令牌对此用户+设备有效,则生成新的 access_token
      2. 返回 access_token 及其 expires_at
      3. 如果刷新令牌无效,则返回无效
      4. 前端会将用户注销。

** 在任何情况下,如果刷新令牌被泄露,它将仅适用于该特定设备/用户。然后,用户可以从他们的列表中停用或删除该设备。此操作将在下次刷新调用时使 refresh_token 无效。