表示没有设置Cookie

Express not setting Cookie

我有2台服务器。一个在 localhost:5555 上托管 next.js 应用程序,另一个在 localhost:4444 上托管 api 的快速服务器.

身份验证 api returns 一个 cookie 但是这没有在 localhost:5555 上的浏览​​器 运行 中设置。

  res.cookie('cokkieName', 'bob', {
        domain: '127.0.0.1:5555',
        maxAge: 900000,
        httpOnly: true,
    });

    res.status(200).json({
        session: jwtSigned,
        role: 'default',
    });

我的 cors 设置是:

const options: cors.CorsOptions = {
    allowedHeaders: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'X-Access-Token', 'Authorization'],
    credentials: true,
    methods: 'GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE',
    origin: 'http://localhost:5555',
    preflightContinue: false,
};

我更愿意使用 api 设置 cookie,而不是通过 next.js。

我试过交替使用 cors 设置,但没有成功。客户端调用使用 axios 并设置了 withCredentials

您尝试做的事情绝对是可能的,问题是 cookie 不是特定于端口的: 所以您应该指定一个域名而不是端口。

如果你在自己的域上设置了一个Cookie(或者你根本不指定),所有后续的请求即使是由不同的端口发起的也会携带这个cookie(仅当withCredentials 设置为 true,不过)。另请注意,如果设置,Cookie 的域必须与当前域或父域完全匹配(localhost 被认为不同于 127.0.0.1

注意:这样做会在Chrome中显示以下警告:

A cookie associated with a cross-site resource at http://example.com/ was set without the SameSite attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.

所以,为未来的网络标准准备你的代码!

我遇到了与 nuxt.js 类似的问题。要使用 express 在浏览器中设置 cookie,我建议使用库 Cookies

在我的例子中,我像这样在 express 中设置 cookies:

setResponseCookie(req, res, token, strategyName) {

    const isHttps = req.protocol === 'https';
    let { cookie: { maxAge } } = config;
    const cookieSettings = isHttps => ({
        maxAge,
        httpOnly: true,
        secure: isHttps,
    });

    const cookies = new Cookies(req, res);
    cookies.set('auth.strategy', strategyName, cookieSettings(isHttps))
    cookies.set('auth.token', token, cookieSettings(isHttps))
}

然后在快速路线中,您可以像这样添加:

let token = sign(user);
this.setResponseCookie(req, res, token, 'local-login')
res.json({ token, status: 'success' });

let token = sign(req.user);
this.setResponseCookie(req, res, token, 'google')
res.redirect(config.client.url);

您不能为其他域设置 cookie,因为那将是一个巨大的安全风险。

但是,如果您正在寻找一种在您的应用程序之间共享 cookie 的方法,那么您唯一的方法就是在这些应用程序之间共享一个域,通过 url 前缀将它们分开或创建一个它们作为其他的子域。

domain.comapi.domain.com。这样,通过在您的 cookie 中指定 domain.com,两个域都可以访问它

如果你担心自己的开发环境,可以在单域中使用Nginxproxy_pass这两个应用程序

如其他答案中所述,您不能在不同的域上设置 cookie,因为这可能存在安全风险。

但是从你的问题来看...

由于 API 服务器是 运行 身份验证逻辑,cookie 应该设置在 API 服务器域,而不是客户端域

因此在您的 API 服务器中,您可以将代码更改为

res.cookie('cokkieName', 'bob', {
        domain: '127.0.0.1:4444',
        maxAge: 900000,
        httpOnly: true,
    });

或者只删除域,因为它默认为服务器域。

res.cookie('cokkieName', 'bob', {
            maxAge: 900000,
            httpOnly: true,
 });

由于您在 localhost:5555 上有一个客户端 运行 并且在 localhost:4444 上有一个 API 服务器 运行,这是一个跨域调用,您需要通过withCredentials 选项 axios 以传递 cookie。您可能无法在浏览器中看到 cookie,因为它可能存在安全风险,但可以在服务器控制台上回显 cookie 值。

axios.get("url",{
    withCredentials: true
    }).then(res => {
            console.log(res);
    });

请注意,凭据选项仅在 Access-Control-Allow-Origin header 不是像 *

这样的通配符时才有效

我创建了一个 server 来模仿您发布的代码。服务器基本上回显了请求cookie。

可以通过这个stackblitz访问。您可以切换 withCredentials 标志以查看响应的差异

我通过如下设置 res.cookie 来解决服务器未设置浏览器 cookie 的问题

res.cookie("Test", "If you see this then it works", {httpOnly: false, secure: true, sameSite: "none"}).json({message: "Finished"});

我通过打开 chrome 开发工具检查是否设置了 cookie,转到应用程序,然后是 cookie,然后是站点 URL。

关于上面的代码,我想优先考虑一些事情。此方法仅适用于以 https 开头的 URL,这意味着如果在像 http://localhost:3000 这样的 URL 上,它将无法解决问题。我不知道 httpOnly 是真还是假是否重要。此外,以这种方式设置 cookie 时需要传入属性 secure: true, sameSite: "none"。将这些值传递给 res.cookie 最终为我解决了这个问题。我还没有在任何地方看到这个解决方案,所以我决定让你知道。

我从 API 获取数据并触发服务器设置浏览器 cookie 的代码对于任何感兴趣的人来说都是这样的。

fetch(domain.com/testSetCookie', {
        method: 'get',
        mode: "cors",
        credentials: 'include' //<-- important
    })
    .then((res) => {
        //console.log(res);
        return; //res.json();
    })
    .then((data) => {
        console.log(data);));
    })
    .catch((err) => {
        console.log("an error happeoned");
        console.log(err);  
    });