javascript - 具有多个客户端平台的应用程序服务器 API 的 session 设计

标签 javascript angularjs node.js web-services rest

我想构建一个支持多个平台的应用程序:桌面应用程序(Mac/PC)、Web(angularJS 前端)和 native 移动应用程序。

所以我在考虑一个应用服务器,为上面的平台提供内部 API。我对如何支持登录/注销有一些假设。如果我的想法是错误的,如果有人可以发表评论,我会很高兴。

  • 对于桌面和移动应用程序,“登录”功能将使用内部 API 来传达凭据,作为返回,将收到一个永久 token 。桌面/移动应用程序将存储 token 并将其用于对应用程序服务器的任何后续请求。从桌面/移动应用程序“注销”后, token 将在服务器端丢弃,而在前端应用程序端被遗忘。
  • 对于 Web 界面,angular 应用程序将在登录后将提供的 token 保留为 cookie,并将加载它并将其用于向应用程序服务器发出的任何请求。

  • 这是一种常见的模式吗?

    最佳答案

    您的基本结构是正确的,但是使用 OAuth2,您将永远不会存储访问 token 。访问 token 通常是授予对 API 访问权限的不透明字符串,将其存储在 cookie 或本地存储中是可以的,但从服务器发出永不过期的 token 是非常不可取的(MITM 攻击可能永远劫持您的身份) .

    为了解决这个问题,OAuth2 实现通常会在访问 token 的同时分发刷新 token 。刷新 token 通常比访问 token 具有更长的到期时间范围(在访问 token 的到期时间和我想说的一个月之间的任何时间)。刷新 token 类似于临时用户密码 - 它们不直接授予对您的 API 的任何访问权限,但是用户可以通过调用您的 OAuth2 刷新 api 向您的系统授权,并获得新的访问权限并使用新的到期时间刷新 token .这使您的应用程序有机会定期重新验证用户声明(可能他们的访问/Angular 色已更改并且他们需要更新声明)。

    JWT 代币

    访问 token 可能是存储在服务器上的不透明字符串,但我强烈建议使用 JWT token 。 JWT token 比不透明(无意义) token 有两个主要优点:

    1. 客户 claim

    在您的客户端应用程序授权后,您需要做的第一件事是查找各种内容来构建您的 UI。 JWT token 的美妙之处在于它们将您的所有用户声明(包括您的应用程序自定义用户声明)作为 JSON 对象有效负载存储在编码字符串中,该字符串可以通过首先在 . 上拆分 token 来在客户端进行解码。 ,将其分解为 [ header, payload, sig ] base 64 编码的字符串。然后,您可以对有效负载字符串进行 base 64 解码并通过 JSON.parse 运行它,这将生成您的声明键值对:

    const access_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ'
    const claims = JSON.parse(atob(access_token.split('.')[1]))
    console.info(claims)


    这允许您的客户端应用程序以原子方式解码用户声明,只不过是访问 token ,而不是使用访问 token 查找有关用户信息的传统模型。使用 JWT,您将立即知道用户的名字、姓氏、用户 ID 以及您想保留在 JWT token 中的任何其他数据。

    2. 无 session

    要使用您的授权 API,您的客户端应用程序将向端点发出请求并发送 'Authorization': 'Bearer access_token' (其中 access_token 是您的访问 token )。在传统应用程序中,必须在服务器端查找访问 token 以验证服务器是否授予了它。关于 JWT token 的另一个很棒的一点是,当它们被发布时,有一个用于对它们进行签名的服务器端 secret 。当服务器需要验证它们时,它只需使用服务器端的 secret 来对它们进行签名,如果通过,服务器将根据解码 token 的声明授予 API 请求。无需在服务器端存储它们,使您的架构更简单。服务器无需在每个授权的 API 请求上与数据库对话。您将绕过许多问题,例如跨 Web 场同步访问 token 或完全存储它们(但是您仍然需要将刷新 token 存储在链接到用户的表中)。

    Cookie 与本地存储

    人们对 cookie 的一个很常见的误解是应该避免使用它们,因为它们会让你打开 CSRF攻击,但通常情况并非如此。发送 session cookie 和基于这些 cookie 的水合物 session 的 Web 表单等系统对 CSRF 攻击是开放的,但如果您正在构建单页应用程序并且您的所有安全检查点都在您的 API 层,您的端点将检查 Authorization不记名 token 的 header ,而不是 cookie。如果您在进行服务器端渲染并在那里使用 cookie 值,您应该了解 CSRF 威胁并实现预防方法。如果你使用cookies,你应该确保它们不要HttpOnly标志设置和 Secure标志设置以保护您免受 MITM 威胁。

    由于您使用的是 node(或至少是 angular),我现在将插入我编写的库 - jwt-autorefresh .这个库的要点很简单,给它你的应用程序刷新机制(客户端代码向你的刷新 api 发出 http 请求并随后将结果存储在 cookie 中)以及你希望在刷新之前刷新 token 的秒数它们的到期时间,它将在您的客户端应用程序上处理自动调度刷新。它在内部解码您的 JWT token 并查看其 exp声明(到期时间)来确定需要多长时间来安排您的刷新。它具有诸如在刷新时间中添加少量抖动的功能,以便所有客户端实例不会同时尝试刷新。

    关于javascript - 具有多个客户端平台的应用程序服务器 API 的 session 设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39794732/

    相关文章:

    javascript - 使用ajax和php将总价格变量限制为2位小数

    javascript - 为 AngularJS Web App 导入 JSON 数据

    javascript - 访问指令的所有 Controller

    node.js - elasticSearch/npm:Elasticdump返回 “self signed certificate”错误

    javascript - CSS 类查找器

    javascript - 在 Sublime Text 2 上切换 Node 构建窗口

    javascript - jQuery 在除数后添加符号

    javascript - this.router 在 AngularJS 2 中未定义

    javascript - 使voiceXML读取服务器返回的结果

    node.js - 使用 node.js 将文件上传到 Firebase 存储中的文件夹中