使用JWT令牌。有更好的方法吗?

时间:2016-07-28 12:50:21

标签: node.js sockets authentication express jwt

我正在通过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令牌指向哪个用户,这样我就可以用它们做一些业务逻辑。

谢谢。

3 个答案:

答案 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的一种极好而方便的方法,但遵循最佳实践至关重要。