Node js、JWT 令牌和背后的逻辑

Posted

技术标签:

【中文标题】Node js、JWT 令牌和背后的逻辑【英文标题】:Node js, JWT token and logic behind 【发布时间】:2014-03-21 04:39:16 【问题描述】:

我正在使用 JWT 来保护节点 js url https://github.com/auth0/express-jwt

要创建 JWT 令牌用户会话,我只需这样做:

-> auth/signup
    -> jwt.sign(user_profile,secret,expireInMinutes:900000000 /*almost never expires*/);

OR 在登录调用的情况下

 -> auth/login
        -> jwt.sign(user_profile,secret,expireInMinutes:900000000 /*almost never expires*/);

每次调用受保护的 url 时,我都会检查由 JWT 中间件自动设置的 req.user

现在我想知道:

1 - 调用 sign() 时 JWT 令牌存储在哪里?

2 - 每次调用受保护的 url 时我都必须验证()令牌吗?如果是,为什么?

3 - 当我为已签名用户设置新令牌时,旧令牌(如果存在)会被删除吗?如果没有设置到期时间或者例如是 5 年怎么办?

4 - 为什么我不能在同一浏览器/应用程序页面上设置新令牌? 如果我注册一个新令牌但令牌匹配(我检查过),我会收到无效签名错误 这就像我不能在同一个浏览器上登录超过 1 个用户

【问题讨论】:

【参考方案1】:

2 - 每次受保护的 url 时,我都必须验证()令牌吗? 叫?如果是,为什么?

是的。但是“验证”是一个有点令人困惑的术语。

    当客户端调用 /authenticate 时,服务器首先根据数据库验证用户凭据以使该用户通过身份验证。而这种“昂贵”的操作在整个令牌生命周期内只执行一次。然后,服务器准备 JSON 对象,保存有用的用户信息,并对其进行加密以获得 JWT 令牌。 此令牌仅向客户端发送一次,存储在浏览器中,然后在每次客户端向 /api 请求时发送回服务器。 在处理客户端 /api 请求期间,服务器必须“验证”令牌的有效性(JWT 会为您完成)。但这并不意味着再次针对数据库检查用户凭据。只需解密令牌以获取 JSON 对象,HMAC-SHA256 验证 - 相当快。 拥有带有有用用户信息(声明)的 JSON 对象,服务器可以允许或不允许此特定用户访问 /api 路由下的请求资源。

在令牌验证期间,不需要对用户凭据进行数据库检查,因为服务器必须信任收到并验证(成功解密)的令牌。识别用户不需要服务器会话存储。

您可以将 JWT 令牌视为简单的会话信息,以加密形式存储在客户端上。但是,如果您需要在用户会话信息中缓存更多数据,我认为您仍然需要在服务器上存储某种会话存储,与 cookie 中的传统会话 ID 相比,JWT 的想法几乎毫无用处。

【讨论】:

【参考方案2】:

您一定已经通过其他用户之前的回复找到了您之前所有问题的答案,但我也会尝试为其他人澄清一下:

1 - 调用 sign() 时 JWT 令牌存储在哪里?

当你呼号时,签名的令牌不会存储在任何地方,它是 由sign函数返回,然后你必须将它发送给客户端 以便 in 可以存储在客户端。 (例如会话存储, 本地存储或cookie)

2 - 每次调用受保护的 url 时我都必须验证()令牌吗?如果是,为什么?

是的,你知道。这个想法是一旦客户拥有令牌,他们将发送 每次他们发出请求时向服务器发送令牌。令牌是 由服务器处理以确定特定客户端是否具有 已经通过身份验证了。

3 - 当我为已签名用户设置新令牌时,旧令牌(如果存在)会被删除吗?如果到期未设置或例如为 5 年怎么办?

与第1点的答案略有相关。调用sign函数 只会生成另一个令牌。令牌的到期时间是 存储在签名令牌本身中。所以每次服务器得到一个令牌 从客户端,它检查过期作为令牌的一部分 确认。重要的是要注意签名的令牌只是 “user_profile”对象作为参数传入 签名,加上额外的字段,如添加到的到期日期 那个对象。

因此,客户端可以在客户端存储多个令牌。他们 只要它们还没有过期,它们都将是有效的。然而 想法是仅在客户端发送令牌时才向客户端发送令牌 在旧的过期后再次进行身份验证。

4 - 为什么我不能在同一浏览器/应用程序页面上设置新令牌?如果我注册一个新令牌但令牌匹配(我检查过),我会收到无效签名错误这就像我不能在同一个浏览器上登录超过 1 个用户

我们的想法是每个浏览器有 1 个用户。因为在这种情况下浏览器 是客户。我想不出你需要的用例 每个浏览器/客户端有多个用户,所以你显然在做 有事吗。这并不是说不可能发送多个 令牌到同一个浏览器/客户端。

【讨论】:

【参考方案3】:

对不起。这应该是对先前答案的评论,但我没有足够的代表发表评论,所以他去了

@sbaang :每次验证的另一个原因是令牌中可能有有趣的“声明2”,例如允许用户访问某些端点,而不是所有端点。因此,在每次验证中,您不仅要验证允许用户访问受保护的 API,但该特定端点不是基于具有有效令牌,而是基于具有明确允许它的令牌。

【讨论】:

【参考方案4】:

    您需要将令牌存储在客户端(本地存储或cookie)

    是的。 HTTP 是无状态的。如果您不每次都验证它,那么有人可能会在没有令牌或使用无效令牌的情况下调用您的 URL。如果您担心性能,HMACSHA256 检查非常快。

    这没有意义,你一定是做错了什么。

【讨论】:

谢谢,对于第 3/4 点,我解决了这似乎是我自己的错误;)关于第 2 点:为什么要验证?我的意思是,/api url 已经受到保护,不是吗?我是否必须在其中添加额外的 jwt 验证? 我的意思是我尝试使用手工制作的标头调用 /api 保护的 url,例如 authorization: Bearer random_hand_made 并且它正确返回 "message":"Invalid token:签名中没有标题 'kerkgekrgkerkgekrgkergkerkg'","code":"invalid_token","status":401,"inner": 还不够吗?

以上是关于Node js、JWT 令牌和背后的逻辑的主要内容,如果未能解决你的问题,请参考以下文章

如何延长node.js中相同jwt令牌的到期时间

如何将 JWT 令牌发送到 node.js 服务器

快速中间件中的 Node.js JWT 刷新令牌

如何将 jwt 令牌发送到 node.js 中的受保护路由

Node.js:登录后在 URL 中发送带有令牌(JWT)的新请求

如何在 Node JS 中使用 jwt 授权具有不同令牌的所有用户