How to destroy JWT Tokens on logout?

I am using jwt plugin and strategy in hapijs.

I am able to create jwt token while login user and authenticate other API using the same token through 'jwt' strategy.

I am setting the token in request.state.USER_SESSION as a cookie where USER_SESSION is a token name. Also, I am not saving these token in the database.

But how can I destroy jwt token at the time of logout?

Please suggest a way.

274947 次浏览

The JWT is stored on browser, so remove the token deleting the cookie at client side

如果您还需要在令牌过期之前从服务器端使其失效,例如帐户删除/阻止/暂停,密码更改,权限更改,用户由管理员注销,请参考 Invalidating JSON Web Tokens中的一些常用技术,如创建黑名单或轮换令牌

You cannot manually expire a token after it has been created. Thus, you cannot log out with JWT on the server-side as you do with sessions.

JWT is stateless, meaning that you should store everything you need in the payload and skip performing a DB query on every request. But if you plan to have a strict log out functionality, that cannot wait for the token auto-expiration, even though you have cleaned the token from the client-side, then you might need to neglect the stateless logic and do some queries. so what's a solution?

  • 为令牌设置合理的过期时间

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

  • 查询为每个授权请求提供了针对 黑名单的令牌

Blacklist

所有不再有效且尚未过期的令牌的“黑名单”。您可以使用一个对文档具有 TTL 选项的 DB,该选项将被设置为标记过期之前的剩余时间。

雷迪斯

Redis 是 黑名单的一个很好的选择,它允许在内存中快速访问列表。然后,在运行于每个授权请求的某种中间件中,您应该检查所提供的令牌是否在 黑名单中。如果是,则应抛出未经授权的错误。如果不是,那么就让它去,JWT 验证将处理它并识别它是过期的还是仍然活动的。

有关更多信息,请参见 Arpy Vanyan 的 使用 JWT 时如何注销.by (信用和参考)

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

但是,如果您想销毁 Node 服务器上的令牌-

JWT 包的问题在于它没有提供任何方法或方法来销毁令牌。

So in order to destroy the token on the serverside you may use JWT-redis 包替代了 JWT

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

它是这样运作的:

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 中提供的一样。

虽然其他答案提供了各种设置的详细解决方案,这可能有助于人谁只是寻找一个一般性的答案。

There are three general options, pick one or more:

  1. On the client side, delete the cookie from the browser using javascript.

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

  3. 在服务器端,更新存储在数据库中的刷新令牌。使用此选项可以从用户登录的所有设备注销用户(他们的刷新令牌将变得无效,必须重新登录)。

You can add "issue time" to token and maintain "last logout time" for each user on the server. When you check token validity, also check "issue time" be after "last logout time".

好了,我尝试了一些我想分享的东西,我认为这是一个非常简单和有效的方法,所以基本上,而不是破坏您的令牌或黑名单,我们可以简单地附加一个随机值到它中间的随机索引,甚至在它的结束像一个随机数(或随机散列数) ,使任何人都难以逆转它,并获得以前有效的令牌,这样做使这个令牌无效,所以用户不会去任何地方,从前端你可以重定向用户再次登录(甚至从后端,如果我喜欢的前端这样做) ,所以用户注销他们得到重定向到登录页面,这一切都很好,这是我的代码。首先,我有一个 auth 中间件,如果令牌(password & username)是 OK 的,它将令牌附加到 req.token,所以每当我调用这个中间件时,用户的令牌将被保存到 req.token

router.post('/logout', auth, async(req, res) => {
try{
let randomNumberToAppend = toString(Math.floor((Math.random() * 1000) + 1));
let randomIndex = Math.floor((Math.random() * 10) + 1);
let hashedRandomNumberToAppend = await bcrypt.hash(randomNumberToAppend, 10);
    

// now just concat the hashed random number to the end of the token
req.token = req.token + hashedRandomNumberToAppend;
return res.status(200).json('logout');
}catch(err){
return res.status(500).json(err.message);
}
});

现在它将连接散列随机数到令牌的末尾,这意味着它不再有效,因此用户将不得不再次登录,因为他们将被重定向到登录页面

如果您只想删除令牌,那么只需从前端应用程序中删除它即可,在您的情况下,清除存储令牌的 Cookie

另一方面,如果您想使令牌无效,有几种方法可以实现,下面是一些方法

(1) 如果所有生成的令牌都存储在后端,那么清除该存储就很简单,如果令牌已经映射到用户,那么只需清除特定用户的令牌即可。

(2) 您可以添加一个日期字段,如“ 无效之前”和 user,这些字段应该在更改密码、从所有设备注销等事件中更新。 只需在这些事件上将 无效之前更新为 currentTime ()。 每次创建新的令牌时,将创建的时间添加到令牌有效负载中, 要在传入请求上验证令牌,只需检查该用户在有效负载中创建的时间是否大于在数据库中创建的 无效之前时间

(3) When you create a new user, create a secret for just that user, then you can sign every user token with that specific secret, and just like in (2) events like changing password, logout from all devices etc, Should create a new secret. 这样,您还可以通过检查令牌签名来使其失效。

(2)(3)的开销是,验证将是一个2步的过程,它涉及数据库读取

编辑: 对于 (3),您可以使用 salt (最终的密钥是 普通秘密 + 特定用户的盐) ,这样您就有办法通过更改 salt 来使单个用户的令牌失效,或者通过更改公共密钥来使所有用户的令牌失效