【问题标题】:Using JWT tokens. Is there a better approach?使用 JWT 令牌。有更好的方法吗?
【发布时间】:2016-12-02 21:04:39
【问题描述】:

我通过 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 令牌指向哪个用户,以便我可以对他们执行一些业务逻辑。

谢谢。

【问题讨论】:

    标签: node.js sockets authentication express jwt


    【解决方案1】:

    一个令牌可以包含任何你想要的信息,这个信息是沿着令牌加密的。

    您可以做的是加密令牌中的用户 ID,当您收到请求时,解密令牌(无论如何在您验证它时完成),然后照常使用用户 ID。

    这样,如果令牌过期,新令牌将具有相同的用户 ID,并且您的代码不会受到影响。

    这是我在我的一个网络应用程序中所做的,它运行良好。但是,我使用的是official jwt module

    【讨论】:

    • 所以我应该在每次请求到达我的套接字端点时解密令牌吗?如果是这样: A. 有没有办法为我的所有 socket.io 端点设置一个全局的中间件之前? B:解密可能是一项消耗 CPU 的任务,是否会对性能产生显着影响?
    • 是的,这就是您验证令牌的方式,而不是通过在服务器端记住它们。对于快递,是的,但我不知道socket.io。有,但不比其他身份验证方案更多。
    • 你不认为可以有不同的方法吗?每次都解密和重新验证令牌听起来不太好,尤其是性能方面,因为我会收到很多套接字调用。 (开发游戏,所以我绑定了很多套接字)我认为套接字的全部目的是识别双方之间的安全握手,因此所有事务都可以安全地完成,而无需在调用期间进行额外的控制。不知道我是不是弄错了,因为我不熟悉实时编程。
    • 性能实在是太低了,JWT 的目标是防止服务器维护一个授权会话列表,客户端必须证明他是授权的。但是您仍然需要验证令牌是否有效。
    【解决方案2】:

    您没有在代码中显示有关如何创建或维护 tokenUserRelations 的任何内容,但是当我听到“全局”时,我的脑海中就会出现一个危险信号。

    JWT 标准包括在令牌本身中嵌入“声明”的概念;您已经在使用 claims 常量这样做了。该数据格式是任意的,只要整个 JWT 得到验证,您的应用程序就可以信任该格式。请注意,您需要在每个请求上验证 JWT。因此,将电子邮件填充到该声明对象中不仅没问题,而且大多数人都会这样做。

    作为旁注,您现在应该注意如何设置“jwt.secret”。您现在拥有的内容将在每次应用程序启动时生成一个新的,这意味着 a)您的所有用户都将被注销并且每次应用程序重新启动时都必须重新登录,并且 b)您无法使用如果将来需要,多个进程或多个服务器。

    最好从环境中提取它(例如环境变量)而不是在应用启动时生成它,除非您只是出于调试目的这样做。

    【讨论】:

    • userRelations 只是一个基本的哈希表,其中键是令牌,值是电子邮件。为了安全起见,我对将信息放在令牌中持谨慎态度,这就是为什么我想将它们保留在服务器端。是的,当我重新启动应用程序时,令牌变得无效。从现在开始,我会将它保存在我的 .env 中。那么,正确/安全的方法是将信息添加到claims 对象中,在每个套接字调用上验证socket.handshake.query.token 并解密令牌以获得信息?
    • 是的,这就是 JWT 令牌的设计用途。
    【解决方案3】:

    除了上述出色的答案之外,如果您决定将 jwt.secret 存储在一个文件中并在代码加载时将其拉入,那么您不要将其添加到您的 git 存储库(或任何其他 VCS)中,这一点也很重要您正在使用)。确保在 .gitignore 文件中包含“jwt.secret”的路径。然后,当您准备好部署生产代码时,您可以按照建议将该密钥设置为环境变量。如果您需要重置它,您将在本地环境中记录该密钥。

    使用 JWT 是保护您的 api 的一种出色且便捷的方法,但遵循最佳实践至关重要。

    【讨论】:

    • 我使用.env。我认为秘密每次都必须不同,因为我遵循的教程就是这样做的。我很高兴我可以依赖.env,因为重启后令牌无效是我心中的一个大问号。 :)
    • 绝对!您还可以通过检查 iat 并强制重新签发(如果有)来设置您的令牌过期。
    • 好的!我会记住这一点。顺便说一句,恭喜你当爸爸了。 :)
    猜你喜欢
    • 2021-02-15
    • 2017-12-10
    • 1970-01-01
    • 2019-10-31
    • 1970-01-01
    • 2018-05-03
    • 2019-02-17
    • 2020-10-20
    • 1970-01-01
    相关资源
    最近更新 更多