如何在注销时销毁JWT令牌?


75

我在hapijs中使用jwt插件和策略。

我可以在登录用户时创建jwt令牌,并通过'jwt'策略使用相同的令牌对其他API进行身份验证。

我将令牌设置request.state.USER_SESSION为cookie,其中USER_SESSION令牌的名称。另外,我没有将这些令牌保存在数据库中。

但是,注销时如何销毁jwt令牌?

请提出一种方法。

Answers:


92

JWT存储在浏览器中,因此删除令牌以删除客户端的cookie

如果您还需要在服务器端使令牌失效之前使令牌失效,例如帐户被删除/阻止/挂起,密码已更改,权限已更改,用户被管理员注销,请查看使JSON Web令牌失效的一些常见技术,例如创建黑名单或旋转令牌


1
我同意你的回答。我通过'reply.state('USER_SESSION',{jwtToken});'在cookie中设置jwt令牌。其中USER_SESSION是cookie名称。因此,您能否建议我应该执行什么命令从hapijs中清除cookie?
加里马

2
您在服务器端,不能强制浏览器删除cookie。但是您可以将值设置为空,并包含expires字段以使cookie值无效。参见stackoverflow.com/questions/5285940/…。您还可以使用javascript在客户端使cookie无效var delete_cookie = function(name) { document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:01 GMT;'; };
pedrofb

37

创建令牌后,您无法使其手动失效。因此,您不能像会话那样使用服务器端的JWT注销。

JWT是无状态的,这意味着您应该将所需的一切存储在有效负载中,并跳过对每个请求的数据库查询。但是,如果您计划具有严格的注销功能,即使您已从客户端清除了令牌,也无法等待令牌自动过期,那么您可能需要忽略无状态逻辑并执行一些查询。那么有什么解决方案?

  • 在令牌上设置合理的到期时间

  • 注销后从客户端删除存储的令牌

  • 在每个授权请求上针对“黑名单”查询提供的令牌

黑名单

所有不再有效且尚未过期的令牌的“黑名单”。您可以在文档上使用带有TTL选项的DB,该数据库将设置为令牌到期之前剩余的时间。

雷迪斯

Redis是blacklist的一个不错的选择,它将允许在内存中快速访问列表。然后,在针对每个授权请求运行的某种中间件中,您应检查提供的令牌是否在The Blacklist中。如果是这样,则应抛出未授权的错误。如果不是,则放开它,JWT验证将处理它并确定它是否过期或仍处于活动状态。

有关更多信息,请参见使用JWT时如何注销。通过Arpy Vanyan


3
如果您将此回答的来源告知您,那就太好了:medium.com/devgorilla/how-to-log-out-when-using-jwt-a8c7823e8a6
Emilio Numazaki

1
大!我的意思是,那里有更多信息,因此对其他人很有用。谢谢!
Emilio Numazaki '20

1
感谢您提供最佳答案之一
-MUFAzmi

15

从客户端注销时,最简单的方法是从浏览器的存储中删除令牌。

但是,如果您想销毁节点服务器上的令牌,该怎么办-

JWT软件包的问题在于它没有提供任何破坏令牌的方法或方式。

因此,为了销毁服务器端的令牌,您可以使用jwt-redis包而不是JWT

这个库(jwt-redis)完全重复了库jsonwebtoken的全部功能,但有一个重要的补充。Jwt-redis允许您将令牌标签存储在redis中以验证有效性。Redis中没有令牌标签会使令牌无效。要销毁jwt-redis中的令牌,有一种destroy方法

它以这种方式工作:

1)从npm安装jwt-redis

2)创建-

var redis = require('redis');
var JWTR =  require('jwt-redis').default;
var redisClient = redis.createClient();
var jwtr = new JWTR(redisClient);

jwtr.sign(payload, secret)
    .then((token)=>{
            // your code
    })
    .catch((error)=>{
            // error handling
    });

3)验证-

jwtr.verify(token, secret);

4)摧毁-

jwtr.destroy(token)

注意:您可以在令牌登录期间提供expiresIn,方法与JWT中提供的相同。


jwt.destroy不是函数
abbasalim

3
jwt没有提供任何销毁方法,我已经在上面进行了详细说明,因此我使用了jwt-redis package.so,如果您看一下代码,我写了jwtr.destroy()
Aman Kumar Gupta

为什么不只在默认数据库中创建一个单独的位置来存储列入黑名单的令牌?为什么要引入Redis?
robertfoenix

如果将所有重新列出的令牌存储在数据库中,那么如何在不访问数据库的情况下销毁该令牌或验证其有效性。然后,在每个带有令牌的传入请求上您需要做的是,首先使用该令牌(如果该令牌不存在)到达数据库,然后相应地发送错误,但是我的问题是为什么要不必要地访问数据库或存储根本不需要的令牌,因此出现了jwt-redis,它将令牌标识符存储在redis中,然后从那里销毁它。销毁后将无法对其进行验证。
阿曼·库玛·古普塔

1

您可以在令牌中添加“发出时间”,并为服务器上的每个用户维护“上次注销时间”。当检查令牌有效性时,还要在“上次注销时间”之后检查“签发时间”。


0

虽然其他答案为各种设置提供了详细的解决方案,但这可能会帮助正在寻找一般答案的人。

共有三个常规选项,选择一个或多个:

  1. 在客户端,使用javascript从浏览器中删除cookie。

  2. 在服务器端,将cookie值设置为空字符串或无用的东西(例如"deleted"),并将cookie过期时间设置为过去的时间。

  3. 在服务器端,更新存储在数据库中的refreshtoken。使用此选项可从所有已登录用户的设备中注销用户(其刷新令牌将变为无效,因此必须再次登录)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.