为啥在通过 Firebase 身份验证传递 id 令牌时,此 CORS 身份验证的 Google Cloud 函数会返回 403?

Posted

技术标签:

【中文标题】为啥在通过 Firebase 身份验证传递 id 令牌时,此 CORS 身份验证的 Google Cloud 函数会返回 403?【英文标题】:Why is this CORS authenticated Google Cloud Function returning a 403 when passing an id token from Firebase authentication?为什么在通过 Firebase 身份验证传递 id 令牌时,此 CORS 身份验证的 Google Cloud 函数会返回 403? 【发布时间】:2020-03-18 00:57:44 【问题描述】:

我已经从google cloud function tutorial 将这个确切的功能部署到我的谷歌云项目中。

在客户端,最终用户使用 firebase signInWithPopup 身份验证进行身份验证。 id 令牌是通过user.getIdToken().then(token => ... // ... 从生成的用户那里获取的。

然后通过角度 httpclient 调用对端点进行调用:

const url = 'https://[MY-PROJECT-SUBDOMAIN].cloudfunctions.net/hello_get/';
this.auth.user.getIdToken().then(token => 
    const httpOptions = 
        headers: new HttpHeaders(
            'Authorization': `Bearer $token`
        )
    ;
    this.http.get(url, httpOptions).subscribe(response => 
        console.log(response);
    , error => 
        console.error(error);
    );
);

对 OPTIONS 预检请求的响应是 403,这让我认为 Google 拒绝了我的 ID 令牌。我在hello_get 函数中添加了一个函数日志。似乎该函数甚至没有被调用,因为当返回 403 响应时该日志从未出现。

当“Cloud Functions Invoker”的功能权限设置为 allUsers 时,云功能通过 CORS 可以正常工作,但是一旦我删除该权限并为 allAuthenticatedUsers 添加权限,并尝试使用 Access-Control-Allow-Credentials': 'true' 传递令牌云函数,返回403。

所以 - 似乎根本原因是谷歌拒绝了预检 OPTIONS 请求。如果是这种情况,使用经过身份验证的 firebase 用户调用经过身份验证的谷歌云函数的推荐方法是什么?

注意:我在这里使用 google cloud 函数而不是 firebase 函数,因为我们需要使用 firebase 函数中不可用的 python3 运行时。

【问题讨论】:

您好!您在客户端中有服务帐户吗?从documentation我了解到,您可以通过 Google Cloud Shell curl https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME \ -H "Authorization: bearer $(gcloud auth print-identity-token --impersonate-service-account=[ServiceAccount])" 使用此命令检查服务帐户是否具有权限 我在客户端确实有服务帐户。如果我在同一个服务帐户上进行 api 调用,是否需要模拟调用?它似乎可以使用 curl 以任何一种方式工作。一旦我使用有角度的 HttpClient 使用 Web 应用程序进行调用,我就会在预检 OPTIONS 调用中得到 403。在这篇文章***.com/questions/51467977/… 上阅读 cmets 让我想知道 gcloud 函数是否需要将 auth 标头包含在预检请求中?我没有看到它在 OPTIONS 调用中传递。 我在 curl 调用和角度 HttpClient 请求之间看到了 2 个不同之处:1) id 令牌似乎不同(我认为这是有道理的,因为我正在从 firebase 获取用户的 id 令牌身份验证,而不是我的服务帐户 ID 令牌)。 2) 浏览器似乎进行了 curl 没有进行的预检 OPTIONS 调用。 嗨,在我提供的链接中,有一个部分是 Authenticating with Firebase,用于 GCP 云功能。 here. 好的,谢谢你指点我回来。更仔细地阅读这些文档,听起来就像在将 Firebase 身份验证与 Google Cloud 功能一起使用时,(1) 功能上的 IAM 设置需要向 AllUsers 开放(而不是我拥有的 allAuthenticatedUsers)和 (2) 令牌验证是使用 firebase_admin 的 auth 库手动完成的。我通过阅读注释得到了这个提示:“与上面的 Google Sign-in 不同,您的函数正在执行身份验证;因此,您需要为未经身份验证的请求付费,因为该函数必须执行验证令牌的工作。” 【参考方案1】:

将 Firebase 身份验证与 Google Cloud 功能结合使用时,用户不会通过 IAM 角色进行身份验证。相反,它们在函数本身内进行身份验证。请注意,根据 Google 的文档,“您将为未经身份验证的请求付费,因为该功能必须执行验证令牌的工作。”要进行设置:

(1) 函数上“Cloud Functions Invoker”的 IAM 权限需要向 allUsers 开放(而不是我拥有的 allAuthenticatedUsers)。

(2) 然后使用 firebase_admin 的身份验证库(docs,供参考和其他语言)手动完成令牌验证,如下所示:

from firebase_admin import auth

def your_function(request):
    decoded_token = auth.verify_id_token(id_token)
    uid = decoded_token['uid']

感谢 Juancki 为我指明了正确的方向。

【讨论】:

这听起来很可怕...为未经身份验证的访问付费? 我同意 - 如果您能找到更好的解决方案,请告诉我 :)

以上是关于为啥在通过 Firebase 身份验证传递 id 令牌时,此 CORS 身份验证的 Google Cloud 函数会返回 403?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我无法通过 Firebase 的身份验证?

在通过 Firebase 身份验证创建用户后,将用户名传递到后端的这两者之间哪种方法更安全?

如何从 Firebase 数据库中获取经过身份验证的用户?

为啥我必须在用户登录后使用 firebase 对用户进行身份验证?

为啥注册用户未在 Firebase 中进行身份验证?为啥用户不能将产品添加到数据库 Firebase?

为啥 Firebase 无法获取 PlayGames AuthCode 并将其传递到其凭据中?