为什么使用 `withCredentials: true` 和 `body` 发送请求会在 Angular HttpClient 中抛出 CORS 错误?

问题描述 投票:0回答:1

我的目标是将请求发送到云功能,云功能将使用

Set-Cookie
标头进行响应,然后浏览器将存储 cookie。

问题在于没有

withCredentials: true
,带有
Set-Cookie
标头的响应将被忽略。

我的结果:

  1. withCredentials: true

预期结果: 服务器将发送带有

Set-Cookie
标头的响应,浏览器将存储 cookie。

实际结果: 浏览器将存储 cookie。

  1. withCredentials: true
    body

预期结果: 服务器将发送带有

Set-Cookie
标头的响应,浏览器将存储 cookie。

实际结果: 服务器抛出错误

Access to XMLHttpRequest at 'http://127.0.0.1:5001/topoint-org/asia-east1/setCookie' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Angular 的代码

  private async fetchSetCookie() {
    if (isPlatformServer(this.platformId)) { return; }

    const observable = this.httpClient.post(
      this.commonEnvironment.functions.setCookie.baseUrl,
      {
        data: {
          idToken: "idToken"
        }
      },
      {
        withCredentials: true,
      }
    )

    observable.subscribe(next => {
      console.log(next);
    })
  }

云函数代码

/* eslint-disable max-len */
import {onRequest} from "firebase-functions/v2/https";
import {CookieOptions, Request, Response} from "express";

/**
 * @bug if we send the request from an angular application, the browser will not store the cookie.
 * if we send the request directly to the cloud function url, the browser will store the cookie.
 */
export const setCookie = onRequest((req, res) => {
  handleCors(req, res);
  const sessionCookie = (Math.random()* 100000000000000000).toString();

  // Set session expiration to 5 days.
  const expiresIn = 60 * 60 * 24 * 5 * 1000;
  const options: CookieOptions = {
    maxAge: expiresIn,
    httpOnly: true,
    secure: true,
    sameSite: "none",
  };
  res.cookie("_rememberme", sessionCookie, options);
  res.send({data: "Set Cookie"});
});

const handleCors = (req: Request, res: Response) => {
  const origin = req.get("origin") ?? "";

  const allowedOrigins = ["https://account.topoint.org", "https://experiences.topoint.org", "https://checkout.topoint.org"];
  if (allowedOrigins.includes(origin)) {
    res.set("Access-Control-Allow-Origin", origin);
  }

  if (process.env.FUNCTIONS_EMULATOR) {
    res.set("Access-Control-Allow-Origin", origin);
  }

  res.set("Access-Control-Allow-Credentials", "true");

  if (req.method === "OPTIONS") {
    // Send response to OPTIONS requests
    res.set("Access-Control-Allow-Methods", "GET");
    res.set("Access-Control-Allow-Headers", "Authorization, Content-Type");
    res.set("Access-Control-Max-Age", "3600");
    res.status(204).send("");
    return;
  }
};
angular express cookies google-cloud-functions
1个回答
0
投票

withCredentials: true
为您的 api 添加了更多安全要求。

您还应该为 CORS 设置另一个标头以允许它

Access-Control-Allow-Credentials: true
© www.soinside.com 2019 - 2024. All rights reserved.