firebase 我无法调用我的私有HTTP云函数(401)承载,而不是承载& SIGNATURE_REMOVED_BY_GOOGLE

yrwegjxp  于 2023-03-19  发布在  Go
关注(0)|答案(1)|浏览(132)

1.我已经创建了一个服务帐户account-name@project-id.iam.gserviceaccount.com
1.我向其中添加了以下角色:云函数调用器和日志编写器。
1.我已经实现了以下云功能:

exports.getRandomInteger = functions
  .region(process.env.REGION)
  .runWith({ memory: "128MB", timeoutSeconds: 60 })
  .https.onRequest((req, res) => {
    return cors(req, res, async () => {
      try {
        validateHttpMethod(req, "GET");

        const authToken = getIdTokenFromRequest(req);

        await verifyIdToken(authToken);

        ...

        return res.status(200).send(randomInteger.toString());
      } catch (err) {
        if (err instanceof HttpError) {
          return res.status(err.statusCode).send(err.message);
        }

        // An internal server error has occurred
        functions.logger.error(err);

        return res.status(500).send(err);
      }
    });
  });

1.在我的云函数的权限部分中,我从云函数调用者角色中删除了allUsers,将其替换为步骤1中创建的帐户account-name@project-id.iam.gserviceaccount.com
1.我使用account-name@project-id.iam.gserviceaccount.com正确登录,并在gcloud CLI中生成了key file
1.我使用cURL调用云函数:

curl -i -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
https://project_location-project_id.cloudfunctions.net/getRandomInteger

1.我收到错误“未授权”:

HTTP/2 401 
vary: Origin
content-type: text/html; charset=utf-8
function-execution-id: hjkhjkfhkfjk
x-cloud-trace-context: xsaajk2h2jjsdk
date: Sat, 18 Mar 2023 02:40:54 GMT
server: Google Frontend
content-length: 12

1.这是我的getIdTokenFromRequest助手:

module.exports = (req) => {
  const authorizationHeader = req.headers.authorization;
  const sessionCookie = req.cookies?.__session;

  // Make sure there is a Bearer token in the Authorization header
  if (!authorizationHeader?.startsWith("Bearer ") && !sessionCookie) {
    throw AuthErrors.unauthorized();
  }

  if (authorizationHeader?.startsWith("Bearer ")) {
    return authorizationHeader.split("Bearer ")[1];
  }

  if (sessionCookie) {
    return sessionCookie;
  }

  throw AuthErrors.unauthorized();
};

1.这是我的verifyIdToken助手:

module.exports = async (token) => {
  try {
    const decodedIdToken = await admin.auth().verifyIdToken(token);

    return decodedIdToken;
  } catch (err) {
    throw AuthErrors.unauthorized();
  }
};

1.由于某种原因,在云函数中记录承载令牌时,我看到:

bearer X.Y.SIGNATURE_REMOVED_BY_GOOGLE

为什么?“bearer”(小写)而不是“Bearer”。签名替换为SIGNATURE_REMOVED_BY_GOOGLE(??)
我做错了什么?我还配置了一个云工作流(使用与步骤1相同的服务帐户)来调用此函数,遵循谷歌文档,但我得到了相同的错误UNAUTHORIZED:

main:
  params: []
  steps:
    - getRandomInteger:
        call: http.get
        args:
          url: https://project_location-project_id.cloudfunctions.net/getRandomInteger
          auth:
            type: OIDC
        result: randomInteger
    - sleep:
        call: sys.sleep
        args:
          seconds: randomInteger
    - returnOutput:
        return: OK
wj8zmpe1

wj8zmpe11#

正如@JohnHanley在他们的评论和this other answer中提到的,这样做是为了安全。
要真正调用函数,所提供的ID令牌必须通过验证。此外,Google Cloud ID令牌和Firebase ID令牌相似,但功能不同,这意味着您无法将其传递给admin.auth().verifyIdToken()并获得正确的结果。
现在,您的函数正在执行,您可以手动解码JWT。

function extractGCloudIdToken(req) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !/^bearer /i.test(authHeader)) {
    throw AuthErrors.unauthorized();
  }

  let decodedIdToken = null;
  try {
    decodedIdToken = JSON.parse(
      Buffer
        .from(
          authHeader.split(" ")[1]?.split(".")[1],
          'base64'
        )
        .toString()
    );
  } catch () { /* suppressed */ }

  if (!decodedIdToken) {
    throw AuthErrors.unauthorized();
  }

  return decodedIdToken;
}

这是这样使用的:

exports.getRandomInteger = functions
  .region(process.env.REGION)
  .runWith({ memory: "128MB", timeoutSeconds: 60 })
  .https.onRequest((req, res) => {
    return cors(req, res, async () => {
      try {
        validateHttpMethod(req, "GET");
        const gcloudIdToken = extractGCloudIdToken(req);

        /* do stuff */

        return res.status(200).send(randomInteger.toString());
      } catch (err) {
        if (err instanceof HttpError) {
          return res.status(err.statusCode).send(err.message);
        }

        // An internal server error has occurred
        functions.logger.error(err);

        return res.status(500).send(err);
      }
    });
  });

相关问题