我正在通过nJWT包使用JWT令牌来使用socket.io-jwt包对我的用户进行Socket.io身份验证。
或多或少,代码看起来像这样。用户通过HTML表单发送POST请求以播放/登录以生成JWT令牌。然后,socket.io客户端使用该令牌进行初始化。
/**
* Create Express server.
*/
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const socketioJwt = require('socketio-jwt');
app.set('jwt.secret', secureRandom(256, {
type: 'Buffer'
}));
app.post('/play/login', (req, res) => {
// validate user's req.body.email and req.body.password
const claims = {
iss: "http://app.dev", // The URL of your service
sub: "user-1", // The UID of the user in your system
scope: "game"
};
const jwt = nJwt.create(claims, app.get("jwt.secret"));
const token = jwt.compact();
new Cookies(req,res).set('access_token', token, {
httpOnly: true,
secure: process.env.ENVIRONMENT === "production"
});
tokenUserRelations[token] = req.body.email;
res.json({
code: 200,
token: token
});
});
/**
* Add Socket IO auth middleware
*/
io.set('authorization', socketioJwt.authorize({
secret: app.get("jwt.secret"),
handshake: true
}));
io.sockets.on('connection', function (socket) {
socket.on('chat message', function (req) {
io.emit("chat message emit", {
email: tokenUserRelations[socket.handshake.query.token],
msg: req.msg
});
});
socket.on('debug', function (req) {
io.emit("debug emit", {
playersOnline: Object.keys(tokenUserRelations).length
});
});
socket.on('disconnect', function (req) {
delete tokenUserRelations[socket.handshake.query.token];
});
});
io.listen(app.get('socket.port'), () => {
console.log('Started! Socket server listening on port %d in %s mode', app.get('socket.port'), app.get('env'));
});
现在,它工作正常,但为了跟踪来自令牌的电子邮件,我必须这样做:
tokenUserRelations[token] = req.body.email;
所以我可以将令牌指向哪个用户。
我感觉在全局对象中保留令牌< - >电子邮件关系会让我头疼,尤其是当令牌/ cookie过期时。
有没有更好的方法呢?我需要知道JWT令牌指向哪个用户,这样我就可以用它们做一些业务逻辑。
谢谢。
答案 0 :(得分:1)
令牌可以包含您想要的任何信息,此信息沿令牌加密。
您可以做的是加密令牌中的用户ID,当您收到请求时,解密令牌(在验证时无论如何都会这样做),并正常使用用户ID。
这样,如果令牌过期,新令牌将具有相同的用户ID,并且您的代码不会受到影响。
这就是我在我的一个网络应用程序中所做的,它运行良好。但是,我使用的是official jwt module
答案 1 :(得分:1)
您不会在代码中显示有关如何创建或维护tokenUserRelations的任何内容,但只要我听到" global"一个红旗在我脑海中升起。
JWT标准包括嵌入'声明的概念。在令牌本身;您已经使用claims
常量进行了此操作。该数据格式是任意的,只要整个JWT得到验证,您的应用就可以信任。请注意,您希望在每个请求中验证JWT。因此,将电子邮件填充到声明对象中并不合适,这是大多数人所做的事情。
作为旁注,你应该小心如何设置你的jwt.secret'马上。你现在拥有的东西会在每次应用启动时生成一个新的,这意味着a)所有用户都将被注销,并且每次应用重启时都必须重新登录,并且b)你无法做到如果您将来需要使用多个进程或多个服务器。
最好从环境中提取(例如env var),而不是在应用启动时生成它,除非您只是为了调试目的而这样做。
答案 2 :(得分:1)
除了上面的优秀答案之外,如果您决定将jwt.secret
存储在一个文件中,并在代码加载时将其添加到您的git存储库(或其他任何内容)中,这一点也很重要。您正在使用的其他VCS)。确保在.gitignore
文件中包含“jwt.secret”的路径。然后,当您准备好部署生产代码时,可以将该密钥设置为建议的环境变量。如果您需要重置它,您将在本地环境中记录该密钥。
使用JWT是保护api的一种极好而方便的方法,但遵循最佳实践至关重要。