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

Jas*_*enX 14 javascript rest web-services node.js angularjs

我想构建一个支持多种平台的应用程序:桌面应用程序(Mac/PC),Web(angularJS前端)和本机移动应用程序.

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

  1. 对于桌面和移动应用程序,"登录"功能将使用内部API来传递凭据,作为回报,将获得永久令牌.桌面/移动应用程序将存储令牌并将其用于对应用程序服务器的任何后续请求.在从桌面/移动应用程序"注销"时,令牌将被丢弃在服务器端,忘记在前端应用程序端.
  2. 对于Web界面,角度应用程序将保留登录后提供的令牌作为cookie,并将其加载并将其用于对应用程序服务器发出的任何请求.

这是一种常见的模式吗?

cch*_*ain 11

您的基本结构是正确的,但是对于OAuth2,您将永远不会永久存储访问令牌.访问令牌通常是一个不透明的字符串,它允许访问您的API,将其存储在cookie或本地存储中是正常的,但是从服务器发出永不过期的令牌将是非常不可取的(MITM攻击可以永久地填补您的身份) .

要解决此问题,OAuth2实现通常会在访问令牌旁边执行刷新令牌.刷新令牌通常具有比访问令牌更长的到期时间帧(在访问令牌的到期时间和我想说的月份之间的任何时间).刷新令牌类似于临时用户密码 - 他们不直接授予您对API的任何访问权限,但是用户可以通过调用您的OAuth2刷新API来授权您的系统,并获得新的访问权限并使用新的到期时间刷新令牌.这使您的应用程序有机会定期重新验证用户声明(可能他们的访问/角色已更改,他们需要更新声明).


JWT代币

访问令牌可能是您存储在服务器上的不透明字符串,但我强烈建议您使用JWT令牌.与不透明(无意义)令牌相比,JWT令牌有两大优势:

1.客户索赔

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

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

这允许您的客户端应用程序以原子方式解码用户声明,而不是使用访问令牌来查找有关用户的信息的传统模型.使用JWT,您将立即知道用户的名字,姓氏,用户ID以及您希望坚持使用JWT令牌的任何其他数据.

2.无会话

要使用您的授权API,您的客户端应用程序将向端点发出请求并发送'Authorization': 'Bearer access_token'(access_token您的访问令牌在哪里).在传统应用程序中,必须在服务器端查找访问令牌以验证服务器是否授予它.关于JWT令牌的另一个令人敬畏的地方是,当它们被发布时,有一个用于签名的服务器端密钥.当服务器需要验证它们时,它只是使用服务器端密钥对它们进行签名,如果它通过,服务器将根据解码的令牌的声明授予API请求.没有必要将它们存储在服务器端,使您的架构更加简单.服务器无需在每个授权的API请求上与数据库通信.您将绕过许多问题,例如跨Web场同步访问令牌或根本不存储它们(但您仍需要将刷新令牌存储在链接到用户的表中).


Cookie与本地存储

人们对cookie有一个很常见的误解是它们应该被避免,因为它们会让你受到CSRF攻击,但事实并非如此.像基于这些cookie发送会话cookie和水合会话的Web表单系统对CSRF攻击是开放的,但如果您构建单页应用程序并且所有安全检查点都在您的API层,您的端点将检查Authorization您的标题不记名,不是饼干.如果您正在进行服务器端呈现并在那里使用cookie值,您应该了解CSRF威胁并实施预防方法.如果你用饼干去,你应该确保他们具备的HttpOnly标志设置和具备安全标志设置,以保护您免受MITM威胁.


既然您正在使用节点(或至少是角度),我现在将插入一个我写的库 - jwt-autorefresh.这个库的重点很简单,给它你的应用程序刷新机制(客户端代码向你的刷新api发出http请求,然后将结果存储在cookie中)以及你希望令牌刷新之前刷新的秒数.它们的到期时间,它将处理客户端应用程序上的自动调度刷新.在内部,它会解码您的JWT令牌,并查看其exp声明(到期时间),以确定计划刷新所需的距离.它具有诸如在刷新时添加少量抖动等功能,以便所有客户端实例不会同时尝试刷新.