未在 cookie 中设置令牌

Posted

技术标签:

【中文标题】未在 cookie 中设置令牌【英文标题】:Token not being set in cookies 【发布时间】:2020-07-09 18:05:49 【问题描述】:

所以我们遇到了一个随机问题,即我们存储在 cookie 中用于身份验证的 JWT 令牌时不时地没有在浏览器中设置。现在 99% 的用户进入登录网页输入他们的详细信息,它会向服务器发送一个请求,服务器会发回他们的用户详细信息和设置到 cookie 中的 JWT 令牌。现在时不时地似乎没有设置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。

然后在前端,我们使用 superagent 来从 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 中没有令牌。随着用户群的增长,该错误变得越来越明显。

【问题讨论】:

您的代码中的jwt 是什么?只是想知道jwt.sign 是否吞下了一些在某些情况下返回空值的错误。 看起来您可能正在使用jsonwebtoken?如果有,是什么版本? 您是否查看了网络选项卡以查看 api 调用是否响应了 cookie?您需要观察没有发生登录时有什么不同 是的,cookie 确实回到了浏览器,我可以在网络选项卡中看到它。 【参考方案1】:

这看起来像是 cookie 问题!

因此,有两种方法可以使用 cookie 在浏览器中保持状态。 会话数据存储在服务器上,通常使用一些键来检索与用户状态相关的值。 Cookies 存储在客户端,并在请求中发送以确定用户状态。 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 的到期日期(格林威治标准时间)。如果未指定或设置为 0, 创建会话 cookie

基本上发生的事情是您没有指定到期时间,因此您的 cookie 被设置为会话 cookie。这意味着每当用户关闭浏览器时,cookie 就会被销毁。

奖金:

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

如果相同的站点属性适用于您的团队,您可能还需要检查它。

【讨论】:

今天试试这个。 这最终解决了问题吗?【参考方案2】:

我没有发现您的代码有任何问题,但过去需要注意的一些事情困扰着我;

确保您的客户端在登录调用仍在进行时不会开始下一次调用。还要确保正确的错误处理以向客户端显示登录失败。 如果您有代理(如 nginx、haproxy),请确保正确配置了 vary 标头 通过配置no-cachemax-age 标头在浏览器中确保服务器上没有发生缓存AND

【讨论】:

感谢您的回复,我已经仔细检查了前端注册代码,它确实在等待第一个请求完成。我什至在提出任何新请求之前添加了超时。我会研究您建议的其他选项

以上是关于未在 cookie 中设置令牌的主要内容,如果未能解决你的问题,请参考以下文章

Set-Cookie 未在我的浏览器中设置 cookie (React + Sanctum)

如何在 axios 拦截器中设置 http cookie?

Spring security + session:接收“Set-Cookie”标头但未在浏览器中设置

反向代理背后的WordPress:未在Safari和IE中设置会话cookie

如何在 ngCookies 中设置 httpOnly 标志?

节点请求在控制台日志中显示 jwt 令牌,但无法在 cookie 中设置