对于我正在从事的一个新的node.js项目,我正在考虑从基于cookie的会话方法(我的意思是,将id存储到用户浏览器中包含用户会话的键值存储中)切换到使用JSON Web Tokens (jwt)的基于令牌的会话方法(没有键值存储)。
这个项目是一个利用socket的游戏。IO——在一个会话(web和socket.io)中有多个通信通道的情况下,有一个基于令牌的会话会很有用。
如何使用jwt方法从服务器提供令牌/会话失效?
我还想了解使用这种范例应该注意哪些常见的(或不常见的)陷阱/攻击。例如,如果这种模式容易受到与基于会话存储/cookie的方法相同/不同类型的攻击。
所以,假设我有以下内容(改编自this和this):
会话存储登录:
app.get('/login', function(request, response) {
var user = {username: request.body.username, password: request.body.password };
// Validate somehow
validate(user, function(isValid, profile) {
// Create session token
var token= createSessionToken();
// Add to a key-value database
KeyValueStore.add({token: {userid: profile.id, expiresInMinutes: 60}});
// The client should save this session token in a cookie
response.json({sessionToken: token});
});
}
口令登录:
var jwt = require('jsonwebtoken');
app.get('/login', function(request, response) {
var user = {username: request.body.username, password: request.body.password };
// Validate somehow
validate(user, function(isValid, profile) {
var token = jwt.sign(profile, 'My Super Secret', {expiresInMinutes: 60});
response.json({token: token});
});
}
--
会话存储方法的注销(或失效)需要更新KeyValueStore
使用指定的令牌创建数据库。
在基于令牌的方法中似乎不存在这样的机制,因为令牌本身将包含通常存在于键值存储中的信息。
如果您希望能够撤销用户令牌,您可以跟踪DB上所有发出的令牌,并检查它们在类似会话的表上是否有效(存在)。
缺点是每次请求都要访问DB。
我还没有尝试过,但我建议使用以下方法来允许令牌撤销,同时将DB命中保持在最小值-
为了降低数据库检查率,根据某种确定性关联将所有已发行的JWT令牌分成X组(例如,按用户id的第一个数字分为10组)。
每个JWT令牌将保存组id和令牌创建时创建的时间戳。例如,{"group_id": 1, "timestamp": 1551861473716}
服务器将在内存中保存所有组id,每个组都有一个时间戳,该时间戳指示属于该组的用户的最后一次注销事件是什么时候。
例如,{"group1": 1551861473714, "group2": 1551861487293,…}
使用带有较旧组时间戳的JWT令牌的请求将被检查是否有效(DB hit),如果有效,将发出一个带有新时间戳的新JWT令牌供客户端将来使用。
如果令牌的组时间戳较新,则相信JWT (No DB hit)。
So -
We only validate a JWT token using the DB if the token has an old group timestamp, while future requests won't get validated until someone in the user's group will log-out.
We use groups to limit the number of timestamp changes (say there's a user logging in and out like there's no tomorrow - will only affect limited number of users instead of everyone)
We limit the number of groups to limit the amount of timestamps held in memory
Invalidating a token is a breeze - just remove it from the session table and generate a new timestamp for the user's group.
---------------- 这个答案一点迟到但可能会帮助别人 ----------------
从客户端,最简单的方法是从浏览器的存储中删除令牌。
但是,如果您想销毁节点服务器上的令牌-
JWT包的问题是它没有提供任何方法或方法来销毁令牌。
您可以使用上面提到的关于JWT的不同方法。但是这里我用的是jwt-redis。
所以为了在服务器端销毁令牌,你可以使用JWT -redis包而不是JWT
这个库(jwt-redis)完全重复了库jsonwebtoken的全部功能,只增加了一个重要的功能。Jwt-redis允许您将tokenIdentifier存储在redis中以验证有效性。redis中缺少tokenIdentifier使得令牌无效。要销毁jwt-redis中的令牌,有一个destroy方法
它是这样工作的:
从npm安装jwt-redis
创建:
Var redis = require('redis');
var JWTR = require('jwt-redis').default;
var redisClient = redis.createClient();
var jwtr = new jwtr (redisClient);
Const secret = 'secret';
const tokenIdentifier = 'test';
const payload = {jti: tokenIdentifier};//你也可以在payload中放入其他数据
jwtr。号(载荷、秘密)
不要犹豫((令牌)= > {
//你的代码
})
.catch((错误)= > {
//错误处理
});
验证:
jwtr。验证(令牌,秘密);
摧毁:
//如果jti在token的签名过程中传递,那么tokenIdentifier else token
jwtr.destroy(tokenIdentifier或token)
注意:
1).你可以在token的登录过程中提供expiresIn,就像JWT中提供的一样。
2).如果在token的签名过程中没有传递jti,那么jti将由库随机生成。
也许这能帮到你或其他人。谢谢。