提问人:Grigor 提问时间:11/8/2023 最后编辑:Grigor 更新时间:11/13/2023 访问量:101
将 Cookie 从前端传递到后端(GCP Cloud Run 上的单独服务)
Passing cookies from frontend to backend (separate services on GCP Cloud Run)
问:
我面临着一个相当有趣的问题。我在 GCP Cloud Run 上分别运行前端和后端服务。FE 是 Next.js 14 + Apollo 客户端 + Supabase 用于身份验证。后端是 Express + Apollo Server Express + TypeGraphQL。
这两个应用都已停靠,然后使用 GitHub Actions 部署到 Cloud Run。
我有一个设置,我在前端的 Apollo 客户端包含要发送到后端的 cookie。然后,我使用 cookie 值对服务器中的某些路径进行身份验证。为此,我通过在创建新的 HttpLink 实例时将凭据设置为 true 来实现此目的。
const httpLink = new HttpLink({
uri: process.env.GRAPHQL_URI,
credentials: 'include'
});
在后端,我有以下内容来配置 CORS。
const corsConfig = {
credentials: true,
origin: ['http://localhost:3000', 'https://frontend-instance.a.run.app'],
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
allowedHeaders:
'Origin, X-Requested-With, Content-Type, Accept, Authorization, Cookie',
};
app.use(cors(corsConfig));
...
const appServer = new ApolloServer({
schema: buildSchemaSync({
resolvers: [
...
]
});
appServer.applyMiddleware({
cors: corsConfig,
app,
path: '/graphql',
});
这在 localhost 中一直按预期工作,但是在部署到生产服务器后,我可以观察到 cookie 不包含在对后端的 graphql 请求中。是什么原因导致的?这是 COR 设置的问题,还是 Cloud Run 的问题?鉴于这在 localhost 中按预期工作,我认为问题不在于设置,而在于 Cloud Run 如何处理 cookie 的传递。
任何指针都将不胜感激。
[编辑]
版本:
NextJS: 14.0.1
Apollo Client: 3.8.0-rc.2
Supabase: 2.38.4
Express: 4.18.2
Apollo Server Express: 3.12.0
TypeGraphQL Prisma: 0.25.1
答:
根据您的设置:
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ Frontend Service (FE) │ │ Backend Service (BE) │
├─────────────────────────────────┤ ├─────────────────────────────────┤
│ - Next.js 14 │ │ - Express │
│ - Apollo Client + HttpLink │ │ - Apollo Server Express │
│ - Supabase (Auth) │ │ - TypeGraphQL │
│ - Dockerized & Deployed │ │ - Dockerized & Deployed │
│ via GitHub Actions │ │ via GitHub Actions │
│ to GCP Cloud Run │ │ to GCP Cloud Run │
│ │ │ │
│ GraphQL Request │ │ │
│ ┌──────────────────────┐ │ │ │
│ │ - Cookies │──────────🞂│ │
│ │ - Authentication │ │ │ │
│ │ Data │ │ │ │
│ └──────────────────────┘ │ │ │
│ │ │ │
│ │ │ GraphQL Response │
│ │ │ ┌──────────────────────┐ │
│ │🞀─────────│ - Data │ │
│ │ │ │ - Session Management │ │
│ │ │ └──────────────────────┘ │
└─────────────────────────────────┘ └─────────────────────────────────┘
假设它在本地环境中按预期工作,它也应该在 GCP Cloud Run 上运行。使用的技术和配置(Next.js、Apollo Client、Express、Apollo Server Express、CORS 设置等)都与云兼容,通常用于基于云的部署。
但是,本地环境和云环境之间的主要区别通常在于域处理、网络配置和安全策略。这可能会影响 Cookie 的处理和传输方式。
我首先要确保前端设置的 cookie 的范围限定为后端可访问的域和路径。
范围限定为特定域或路径的 Cookie 可能不会发送到其他域。
如果您的生产环境是 HTTPS(可能适用于 Cloud Run),请确保使用 Cookie 设置了适当的 SameSite
属性。这些属性对于跨站点请求通常是必需的。Secure
SameSite=None; Secure
document.cookie = "name=value; domain=your-domain.com; path=/; SameSite=None; Secure";
使用浏览器开发人员工具检查网络流量。在响应中查找标头,在请求中查找标头,以验证 Cookie 是否正确设置和发送。Set-Cookie
Cookie
虽然 CORS 设置看起来正确,但请确保生产中的前端 URL 正确列在 CORS 配置的数组中。origin
查看 Cloud Run 日志,查看与 Cookie 处理或 CORS 相关的任何警告或错误。有时,生产环境具有额外的安全措施,可能会干扰 Cookie 传输。
如果 Cookie 仍然存在持续性问题,请考虑在标头中使用身份验证令牌(如 JWT)作为可能的替代方法。Authorization
- 我已经确认源列表具有指向前端的正确 URL。
- 我已经更新了我的代码,以在前端手动设置带有标志的 authToken cookie。观察到没有变化,cookie 仍然没有通过。
SameSite=None; Secure
- 我已经使用 Authorization 标头方法作为解决方法。
这种方法对我来说的问题是,因为我有一个 SPA,并且该部分是在服务器组件中完成的,因此我可能没有获得最新的令牌。
我也尝试从后端预检返回,这是完整列表:.仍然没有骰子。
Same-Site
Origin, X-Requested-With, Content-Type, Accept, Authorization, Cookie, Set-Cookie
鉴于其他详细信息:
- 由于源列表已确认包含正确的 URL,因此 CORS 配置不太可能成为问题。
使用标志设置 cookie 应该有助于跨域 cookie 传输,但由于这没有解决问题,它指向了另一个原因。
authToken
SameSite=None; Secure
使用 Authorization 标头是一种可行的解决方法,但担心在 SPA 上下文中无法获取最新的令牌是有效的。
在后端预检响应中添加到允许的标头列表中是一个很好的步骤,但由于它不起作用,因此问题可能不在于 CORS 标头本身。
Set-Cookie
因此,问题可能出在 Cloud Run 上的特定部署或网络配置中,也可能出在浏览器在生产环境中处理 Cookie 的方式上。
详细检查浏览器的网络活动可能很有用,以查看 cookie 是否正在设置但未发送,或者它们是否因安全策略而被阻止。
并查看可能影响 Cookie 处理的任何特定 Cloud Run 设置或日志。
如果我将后端查询代理到前端的某个路径,比如(使用 nextjs config)怎么办。瞧,饼干现在正在发送!
/api
这确实涉及巧妙地使用 Next.js 的重写规则通过前端服务代理 GraphQL 请求。
通过将请求定向到前端的路径(例如,),然后将此路径重写到后端 GraphQL URI,它们可以有效地确保范围限定在前端域的 cookie 包含在对后端的请求中。/api
这种方法利用了 cookie 随请求发送到同一来源(在本例中为前端)的事实,并利用 Next.js 的功能将请求重写到外部 API。
通过前端代理请求,解决了跨域设置中未发送 cookie 的问题,这是现代 Web 开发中的常见挑战。
评论
authToken
SameSite=None; Secure
Origin, X-Requested-With, Content-Type, Accept, Authorization, Cookie, Set-Cookie
该解决方案涉及使用 NextJs 的重写规则。我编辑并添加了以下内容:next.config.js
const nextConfig = {
...,
async rewrites() {
return [
{
source: '/api',
destination: process.env.GRAPHQL_URI,
},
];
},
};
然后,在我创建后端 HTTP 链接的代码中,我简单地更新了 URI,如下所示:
const httpLink = createHttpLink({
uri: BACKEND_API_PROXY_URI,
credentials: 'include',
});
哪里像这样BACKEND_API_PROXY_URI
http://localhost:3000/api
部署到 Cloud Run 后,我注意到 Cookie 现在可以正确发送!
评论