如何允许 express 后端 REST API 在使用 axios 的反应前端中设置 cookie?
How to allow express backend REST API to set cookie in a react frontend which is using axios?
后端
我正在尝试使基于 JWT cookie 的身份验证工作。我目前正在后端 API.
中执行以下 cookie 设置作为登录路由的一部分
res.cookie('authCookie', token, {maxAge: 900000, httpOnly: true});
稍后当我授权任何其他请求时,我正在读取此 cookie 并在 passport-jwt
策略中对其进行测试。
我在 postman 中完成了这项工作 - 当我执行登录并访问安全路由时 - 它工作得很好 + cookie 也在 postman 中设置。
前端
现在,我在前端执行以下调用堆栈只是为了测试工作,
axios.post("http://localhost:3001/login", logInParams, config)
.then(result => {
// User is logged in so push them to the respective dashboard
console.log(result);
axios.get("http://localhost:3001/user/profile")
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
return;
})
})
.catch(err => {
console.log(err)
return;
});
所以基本上,我让用户登录并且工作得很好 - 我得到了预期的 JSON 响应,但是调用应该设置一个 cookie,但它不是,因此下一个 axios.get
调用未成功返回。尽管出于某种原因,我看到 session
cookie 和 CSRF
cookie。只有这个 authCookie
或 jwt-cookie 没有设置。
一些额外的细节
我正在使用带有默认参数的 cors - 这可能是一个错误吗?或者我对 axios 有什么改变吗?我已经看到了一些答案,但作为 MERN 的新手,我并不真正理解它们。有没有人知道这个或者经历过并解决了?
我认为你应该在 res.cookie('authCookie', token, {maxAge: 900000, httpOnly: true});
您是否 运行 服务器来自与提供客户端的端口不同的端口(即:localhost:3000
上的 webpack-dev-server 运行 和 localhost:3001
)?这看起来像是 same-site
cookie 问题。在某些浏览器的最新版本中,例如 Chrome,当此浏览器来自不同的来源站点时,cookie 设置将被阻止。这是出于安全考虑;您可以了解有关同站点 cookie 的更多信息 here.
浏览器中所做的更改与它们为名为 same-site
的 cookie 策略 属性 提供的默认值有关。旧的解决方法是默认将来自不同来源的所有 cookie 视为 None
,但去年它更改为将 same-site
策略视为 Lax
,而没有 same-site
策略服务器未明确提供。这是浏览器的理想行为,因为它有助于防止第三方站点使用服务器提供的 cookie,但您可以通过不同的方式对其进行编辑:
- 更改浏览器设置的默认同站点策略(有关同站点 cookie 的文章有解释)。
- 从服务器发送
same-site:'None'
。 Express has a way to do so explaind on its docs。请记住,当 cookie 未标记为 Secure
时,浏览器也有一个忽略 same-site:'None'
的新策略,这需要使用 HTTPS
(我想可以在您的浏览器中编辑此行为如果您想在使用 HTTP
) 时检查设置)。
显然,任何要求用户更改浏览器设置的策略都是行不通的,因此 运行 HTTPS
和 Secure
cookie 对 same-site:'None'
是强制性的.
你总是有使浏览器和客户端同源的方法,所以你不会有任何问题 same-site
(即 Express 服务器返回生产的 index.html构建您的客户端作为其主要静态)。我还没有找到任何方法来将 CORS 模块配置为具有默认的相同站点 cookie 策略(或其唯一用作中间件来更改它),可能不是它的目的,但您可以尝试 adding a dynamic origin config.
据我所知,Postman does not support the same-site cookie property yet,这样就可以解释为什么它在 Postman 上工作,但在浏览器上不工作。
从外观上看 - 这似乎与 cors 的工作方式有关,我添加以下答案以帮助遇到它的其他人。稍后谢谢我:)
服务器端
您的服务器中将有一个如下所示的 cors,
app.use(cors());
您必须将 credentials
设置为 true 并设置 allowedHeaders
和 origin
,如下所示,
app.use(cors({
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization'],
origin: ['http://localhost:3000']
}));
这是因为如果服务器端和客户端在同一个端口,一般情况下是不允许在浏览器中设置cookies的。要处理此问题,服务器端需要上述内容。
客户端
我们还必须在发送请求时传递 cookie,要使用 axios
执行此操作,只需在您的 React 应用程序的 index.js
中添加以下内容,
axios.defaults.withCredentials = true;
后端
我正在尝试使基于 JWT cookie 的身份验证工作。我目前正在后端 API.
中执行以下 cookie 设置作为登录路由的一部分res.cookie('authCookie', token, {maxAge: 900000, httpOnly: true});
稍后当我授权任何其他请求时,我正在读取此 cookie 并在 passport-jwt
策略中对其进行测试。
我在 postman 中完成了这项工作 - 当我执行登录并访问安全路由时 - 它工作得很好 + cookie 也在 postman 中设置。
前端
现在,我在前端执行以下调用堆栈只是为了测试工作,
axios.post("http://localhost:3001/login", logInParams, config)
.then(result => {
// User is logged in so push them to the respective dashboard
console.log(result);
axios.get("http://localhost:3001/user/profile")
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
return;
})
})
.catch(err => {
console.log(err)
return;
});
所以基本上,我让用户登录并且工作得很好 - 我得到了预期的 JSON 响应,但是调用应该设置一个 cookie,但它不是,因此下一个 axios.get
调用未成功返回。尽管出于某种原因,我看到 session
cookie 和 CSRF
cookie。只有这个 authCookie
或 jwt-cookie 没有设置。
一些额外的细节
我正在使用带有默认参数的 cors - 这可能是一个错误吗?或者我对 axios 有什么改变吗?我已经看到了一些答案,但作为 MERN 的新手,我并不真正理解它们。有没有人知道这个或者经历过并解决了?
我认为你应该在 res.cookie('authCookie', token, {maxAge: 900000, httpOnly: true});
您是否 运行 服务器来自与提供客户端的端口不同的端口(即:localhost:3000
上的 webpack-dev-server 运行 和 localhost:3001
)?这看起来像是 same-site
cookie 问题。在某些浏览器的最新版本中,例如 Chrome,当此浏览器来自不同的来源站点时,cookie 设置将被阻止。这是出于安全考虑;您可以了解有关同站点 cookie 的更多信息 here.
浏览器中所做的更改与它们为名为 same-site
的 cookie 策略 属性 提供的默认值有关。旧的解决方法是默认将来自不同来源的所有 cookie 视为 None
,但去年它更改为将 same-site
策略视为 Lax
,而没有 same-site
策略服务器未明确提供。这是浏览器的理想行为,因为它有助于防止第三方站点使用服务器提供的 cookie,但您可以通过不同的方式对其进行编辑:
- 更改浏览器设置的默认同站点策略(有关同站点 cookie 的文章有解释)。
- 从服务器发送
same-site:'None'
。 Express has a way to do so explaind on its docs。请记住,当 cookie 未标记为Secure
时,浏览器也有一个忽略same-site:'None'
的新策略,这需要使用HTTPS
(我想可以在您的浏览器中编辑此行为如果您想在使用HTTP
) 时检查设置)。
显然,任何要求用户更改浏览器设置的策略都是行不通的,因此 运行 HTTPS
和 Secure
cookie 对 same-site:'None'
是强制性的.
你总是有使浏览器和客户端同源的方法,所以你不会有任何问题 same-site
(即 Express 服务器返回生产的 index.html构建您的客户端作为其主要静态)。我还没有找到任何方法来将 CORS 模块配置为具有默认的相同站点 cookie 策略(或其唯一用作中间件来更改它),可能不是它的目的,但您可以尝试 adding a dynamic origin config.
据我所知,Postman does not support the same-site cookie property yet,这样就可以解释为什么它在 Postman 上工作,但在浏览器上不工作。
从外观上看 - 这似乎与 cors 的工作方式有关,我添加以下答案以帮助遇到它的其他人。稍后谢谢我:)
服务器端
您的服务器中将有一个如下所示的 cors,
app.use(cors());
您必须将 credentials
设置为 true 并设置 allowedHeaders
和 origin
,如下所示,
app.use(cors({
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization'],
origin: ['http://localhost:3000']
}));
这是因为如果服务器端和客户端在同一个端口,一般情况下是不允许在浏览器中设置cookies的。要处理此问题,服务器端需要上述内容。
客户端
我们还必须在发送请求时传递 cookie,要使用 axios
执行此操作,只需在您的 React 应用程序的 index.js
中添加以下内容,
axios.defaults.withCredentials = true;