未在Cookie中设置令牌

时间:2020-03-29 09:45:03

标签: javascript node.js reactjs express cookies

因此,我们有一个随机的问题,即我们不时在浏览器中设置存储在Cookie中用于身份验证的JWT令牌。现在,用户有99%的时间进入登录网页并输入其详细信息,它将请求发送到服务器,服务器将其用户详细信息和JWT令牌集发送回cookie。现在似乎不时地没有设置cookie。现在几乎所有浏览器都发生了随机性,但没有任何原因。它发生在我们的本地,暂存和生产环境中。 (出于隐私原因,我删除了一些代码)

后端验证服务是使用Node和ExpressJS构建的,它使用以下代码设置令牌:

module.exports.signIn = async function(req, res, next) {
  try {
    const { email, password } = req.body;
    if (!email || !password)
      throwBadRequest("Please enter a valid email and password");

    const data = await Users.get(`?email=${email.toLowerCase().trim()}`);

    const { name, val, options } = await Token.generateCookieParams(data);
    res.cookie(name, val, options);

    return res.json(toDTO(data));
  } catch (err) {
    next(err)
  }
};

如果有帮助,我们正在使用中间件cookie解析器。这是设置令牌的代码:

async function generateFor(user, expireTime, special = null) {
    const payload = { id: user._id, type: user.type, account: user.account };
    if (user.entity) {
      payload.entity = user.entity;
    }
    if (special) {
      payload.special = special;
    }
    const token = await jwt.sign(payload, config.secret, {
      expiresIn: expireTime
    });
    return token;
  }

async function generateCookieParams(user) {
    const expireTime = 60 * 60 * 12; // 12 hour
    const token = await Token.generateFor(user, expireTime);
    return { name: config.tokenKey, val: token, options: { httpOnly: true } };
  }

我们正在使用中间件cors在express应用中管理cors,并将选项凭据设置为true。

然后在前端,我们使用超级代理从react应用发出所有请求,我们也使用了Axios,但是存在相同的问题。联网的基本代码在前端看起来像这样:

import superagent from "superagent";

const superagentManager = {};

/**
 * POST
 * @param {string} path => the path for the post request
 * @param {object} data => the object you are posting in json format
 */
superagentManager.post = async (path, data) => {
  return await superagent
    .post(path)
    .withCredentials()
    .type("application/json")
    .send(data);
};

/**
 * GET
 * @param {string} path => the path for the get request
 */
superagentManager.get = async path => {
  return await superagent
    .get(path)
    .withCredentials()
    .type("application/json");
};

/**
 * PATCH
 * @param {string} path => the path for the patch request
 * @param {object} data => the object you are posting in json format
 */
superagentManager.patch = async (path, data) => {
  return await superagent
    .patch(path)
    .withCredentials()
    .type("application/json")
    .send(data);
};

/**
 * DELETE
 * @param {string} path => the path for the delete request
 */
superagentManager.delete = async path => {
  return await superagent
    .delete(path)
    .withCredentials()
    .type("application/json");
};

export default superagentManager;

如果有人可以帮助我,将不胜感激。该系统正常运行,但每隔50次登录中就有1次未在浏览器中设置令牌。因此,用户对象是从登录请求中返回的,但是由于cookie中没有令牌,因此之后立即发生的其他请求将引发错误。随着用户群的增长,该漏洞变得越来越引人注目。

2 个答案:

答案 0 :(得分:2)

这看起来像一个cookie问题!

因此,有两种方法可以通过Cookie在浏览器中保持状态。 会话数据存储在服务器上,通常使用一些键来检索与用户状态有关的值。 Cookie 存储在客户端,并在请求中发送以确定用户状态。 ExpressJS支持同时使用这两种功能。对于JWT,您当然想使用cookie方法!

让我们先看看您的cookie选项:

// return { name: config.tokenKey, val: token, options: { httpOnly: true } };

const cookieOptions = {
    httpOnly: true
}

到目前为止,这看起来不错。您正在关注best practices about storing tokens as http only,但是要正确存储cookie,可能需要在cookie选项中添加更多内容。

Here is a link to cookie options in the express docs。查看“过期”的说明:

该Cookie在GMT中的到期日期。如果未指定或设置为0, 创建会话cookie

从本质上讲,您没有指定到期时间,因此您的cookie被设置为会话cookie 。这意味着,只要用户关闭浏览器,cookie就会被破坏。

奖金:

  • 如果您的站点使用HTTPS,请确保将cookie设置为secure: true

  • 如果适用于您的团队,您可能还想检查sameSite属性。

答案 1 :(得分:1)

我看不到您的代码有什么问题,但是过去需要注意的一些事情使我困扰;

  • 确保在登录呼叫仍在发生时,您的客户端不会启动下一个呼叫。还请确保正确的错误处理以向客户端显示登录失败。
  • 如果您有代理服务器(如nginx,haproxy),请确保vary标头配置正确
  • 通过配置no-cachemax-age标头来确保浏览器中服务器 AND 上没有缓存发生