为何使用@angular/fire/functions的httpsCallable时Set-Cookie被忽略?
问题分析与解决方案
核心问题
要实现account.topoint.org、experiences.topoint.org等子域间的认证共享,需要让浏览器正确存储跨域请求返回的session Cookie,但当前浏览器未保存返回的Cookie,根源在于三个关键配置缺失:
- Cookie未指定父域,默认绑定到Cloud Function域名而非
topoint.org,导致子域无法访问 - Angular跨域请求未开启凭证携带,浏览器默认不会保存跨域Cookie
- CORS配置未允许凭证传递,且请求携带凭证时
Access-Control-Allow-Origin不能设为*
修复步骤
1. 修正Cloud Function的Cookie配置
给Cookie添加domain和path属性,确保绑定到父域,所有子域都能访问:
// createSessionToken函数中设置Cookie的部分 const options = { maxAge: expiresIn, httpOnly: true, secure: process.env.FUNCTIONS_EMULATOR === "true" ? false : true, domain: ".topoint.org", // 前置点表示所有topoint.org的子域 path: "/" // 允许所有路径访问该Cookie }; res.cookie("session", sessionCookie, options);
2. 修正CORS配置
更新handleCors函数,添加允许凭证传递的响应头,同时确保OPTIONS预检请求也返回该头:
const handleCors = (req: Request, res: Response) => { const allowedOrigins = ["https://account.topoint.org", "https://experiences.topoint.org", "https://checkout.topoint.org"]; const origin = req.get("origin") ?? ""; if (allowedOrigins.includes(origin)) { res.set("Access-Control-Allow-Origin", origin); res.set("Access-Control-Allow-Credentials", "true"); // 允许凭证传递 } if (process.env.FUNCTIONS_EMULATOR) { // 本地开发指定具体前端域名,禁止使用* res.set("Access-Control-Allow-Origin", "http://localhost:4200"); res.set("Access-Control-Allow-Credentials", "true"); } if (req.method === "OPTIONS") { res.set("Access-Control-Allow-Methods", "POST, OPTIONS"); // 支持POST请求 res.set("Access-Control-Allow-Headers", "Authorization, Content-Type"); res.set("Access-Control-Allow-Credentials", "true"); // OPTIONS预检必须包含该头 res.set("Access-Control-Max-Age", "3600"); res.status(204).send(""); return; } };
3. 修正Angular HttpClient请求配置
在POST请求中添加withCredentials: true,让浏览器保存跨域返回的Cookie:
private async createSessionToken(idToken: string) { if (isPlatformServer(this.platformId)) { return; } const observable = this.httpClient.post( "https://asia-east1-topoint-org.cloudfunctions.net/createSessionToken", // 替换为生产环境Cloud Function域名 { data: { idToken: idToken, } }, { withCredentials: true } // 关键:开启凭证携带 ); observable.subscribe(response => { console.log(response); }); }
关于httpsCallable的说明
Firebase的httpsCallable默认不支持携带/接收Cookie,因为它基于fetch API且未配置credentials: 'include',因此在需要跨域传递Cookie的场景下,建议直接使用Angular HttpClient。
内容的提问来源于stack exchange,提问作者Jason Rich Darmawan
相关产品推荐
相关产品推荐

