如何在不收集令牌的情况下使 JWT 令牌失效
今天我在dev.to上阅读了这篇文章,因为在我看来,这是一个每个人都应该关心的话题。
作者很好地解释了所有要点,但没有主动提出我认为最实用的使令牌无效的方法,所以我会尽力在这里补充那篇文章。
不具吸引力的提议
我们先来看看大家不喜欢的地方:通过在数据库表中将令牌列入黑名单来使令牌失效。这很占空间,因为令牌可能会变得很大,迫使你进行额外的检查,导致表空间不断增大。
嗯,除了一个问题以外,其他所有问题都可以消除。
提议
有一种更好的方法来使 JWT 无效,那就是通过其创建时间。
所有 JWT 都应该包含iat
声明issued at
。这是令牌颁发/创建的时间。与其在DB/Redis/Memcached中设置令牌黑名单,不如创建一个更小的列表/表,其中包含用户条目以及令牌对该用户有效的最短日期。此表每个用户只有一个条目。如果用户多次经历令牌失效,则只有最近一次有效。因此,该表将逐渐增长到最大用户数。
不仅如此,当我们确定所有先前发行的令牌(需要列入黑名单的令牌)都已过期后,还可以删除此表中的记录,从而使表更小。这是一个简单的计算:如果now() - token TTL > stored timestamp
,则可以安全地删除该记录。
因此,让我们根据问题列表来回顾一下我的承诺:
问题 | 解决了吗? |
---|---|
记录大小可能很大(由于令牌的大小) | ✅ |
表格无限制增长 | ✅ |
额外检查(数据库或缓存调用) | ❌ |
看起来我已经送货了。
试驾提案
用户 X 是管理员,但你刚刚收到老板的邮件,要求将用户 X 降级为普通用户。于是,你在我们的魔法表中添加了以下记录:
{
"userId": 123456,
"BlTimestamp": "2022-12-04T19:27:00Z"
}
}
现在,当你的安全微服务(或子系统,或其他什么)收到使用用户 X 30 分钟前签发且仍然有效的令牌的请求时,就会进行iat
检查。“好吧,好吧,好吧,看看是谁又回来要东西了,用户 X 想耍大帅哥删除东西。这个令牌是在 签发的2022-12-04T18:58:05Z
,我有记录说,如果是在 之前签发的,我就不应该接受你发来的令牌2022-12-04T19:27:00Z
。不行不行。这是 HTTP 401 错误。重新进行身份验证。”
简单多了,对吧?如果你想让我在ASP.Net中演示一下,请在评论区留言。下面是NodeJS的核心代码示例。
validateToken: function (token) {
let verifiedToken = null;
try {
verifiedToken = jwt.verify(token, config.jwt.secret);
}
catch (e) {
console.error('Error verifying token: %o', e);
return {
valid: false
};
}
// Standard validation succeeded. Let's see about the iat:
const globalInv = jwtInvalidationService.globalInvalidation();
const userInv = jwtInvalidationService.userInvalidation(verifiedToken.name);
let minimumIat = Math.max(globalInv, userInv);
if (minimumIat) {
minimumIat = new Date(minimumIat);
console.debug('Token subject to minimum issued at verification: %s', minimumIat);
const issuedAt = new Date(verifiedToken.iat * 1000);
if (issuedAt < minimumIat) {
console.warn("Token issued at %s for user %s is not acceptable.", issuedAt, verifiedToken.name);
return {
valid: false
};
}
}
return {
valid: true,
token: verifiedToken
};
}
注意:我知道这段代码可能不太直观,因为有些地方不太明显。例如,令牌内部是什么,它的工作原理,jwtInvalidationService
以及如何添加失效机制,这些在代码片段中都没有提到。如果您不想错过即将发布的文章,其中包含完整的项目示例(大约 200 行代码),请务必关注我。
全局无效
相同的表和机制可以使所有令牌失效。只需添加一个不与用户 ID 关联的黑名单时间戳即可。然后,只需确保您收到的任何令牌都是在此时间之后发出的即可。如果您全局失效,该表实际上可能会被截断,只留下全局记录,因为全局失效将取代所有现有的每个用户黑名单记录,从而保持表的紧凑性。
更多内容
如果需要,您可以对此进行更多创意。您可以通过检查声明(令牌)或数据库数据中的角色列表来改进此模型,使其仅考虑特定安全组的令牌失效。各位,一切皆有可能。
编码愉快!
鏂囩珷鏉ユ簮锛�https://dev.to/webjose/how-to-invalidate-jwt-tokens-without-collecting-tokens-47pk