使用 firebase admin Auth 在 HTTPS 调用期间进行云功能和客户端身份验证

Cloud Function & client authentication during HTTPS Call using firebase admin Auth

背景: 我有三个实体(语言: JS):

  1. 浏览器客户端
  2. Google 云函数
  3. 一个 HTTP 服务器[有 Firebase admin Auth 中间件]

所以,从 1 和 2,我想使用 HTTPS 调用与 3 通信。 因为 3 已经有 admin Auth,所以我可以授权来自 clients(1) 的调用。

但我想知道如何授权来自 google 云函数的调用(2),以便我可以安全地与两个实体通信。

令牌授权中间件:

const validateFirebaseIdToken = async (req: any, res: any, next: any) => {
  console.log(await auth.getCredentials());
  if (
    (!req.headers.authorization ||
      !req.headers.authorization.startsWith("Bearer ")) &&
    !(req.cookies && req.cookies.__session)
  ) {
    console.log(
      "No Firebase ID token was passed as a Bearer token in the Authorization header." +
        "Make sure you authorize your request by providing the following HTTP header:" +
        "Authorization: Bearer <Firebase ID Token>" +
        'or by passing a "__session" cookie.'
    );
    res.status(403).send("Unauthorized 1");
    return;
  }

  let idToken;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith("Bearer ")
  ) {
    console.log('Found "Authorization" header');
    // Read the ID Token from the Authorization header.
    idToken = req.headers.authorization.split("Bearer ")[1];
  } else if (req.cookies) {
    console.log('Found "__session" cookie');
    // Read the ID Token from cookie.
    idToken = req.cookies.__session;
  } else {
    // No cookie
    res.status(403).send("Unauthorized 2");
    return;
  }

  try {
    const decodedIdToken = await admin.auth().verifyIdToken(idToken);
    req.user = decodedIdToken;
    next();
    return;
  } catch (error) {
    console.log("Error while verifying Firebase ID token:" + error);
    res.status(403).send("Unauthorized 3");
    return;
  }
};

听起来您正试图从云函数向您的服务器发出 API 调用。如果您正在使用 functions.https.onCall 可调用函数,它会自动反序列化请求正文并验证身份验证令牌。因此,除非您明确传递它们,否则您不会获得实际的 ID 令牌。

要将用户信息传递到您的服务器,您可以尝试以下任一方法:

  1. 将 ID Token 显式传递给云函数,然后传递给您的 API,这将再次验证 ID Token。

  2. 如前所述,可调用的云函数将自动验证用户并将 DecodedIdToken 添加到 context.auth.token。由于用户已经通过身份验证,您可以简单地将用户的 UID(以及其他必要的声明)传递到您的服务器以进行进一步处理。但是,这意味着您必须以接受 UID 而不是令牌的方式配置中间件,令牌可以通过使用某些 UID 直接向服务器发出随机请求而被滥用。

如果您使用方法 2,则必须确保请求仅来自您的云功能。这可以通过在云功能和服务器之间共享一个秘密来完成,您可以将该秘密附加到您向服务器发出的每个 HTTP 请求,类似于 API 密钥。