Firebase:删除用户分析数据 - userdeletionRequests:upsert - GDPR

Firebase: Delete user analytics data - userdeletionRequests:upsert - GDPR

我的问题是,如何使用“Google 用户删除 API”及其方法从 firebase 中删除用户分析数据:userdeletionRequests:upsert?这对我完全履行 GDPR 很重要。

我尝试搜索这个,但没有找到将它与“NodeJS”和“firebase-cloud-functions”结合使用的解决方案。

我最大的问题是,我如何获得访问权限、令牌,这是我目前拥有的:

const accessToken = (await admin.credential.applicationDefault().getAccessToken()).access_token;

return ky.post(constants.googleUserDeletionURL, {
    body: JSON.stringify({
        kind: "analytics#userDeletionRequest",
        id: {
            type: "USER_ID",
            userId: uid,
          },
          propertyId: constants.googleUserDeletionPropertyId,
    }),
    headers: {
        "Authorization": `Bearer ${accessToken}`,
    },
}).catch((err) => {
    functions.logger.log(`An Error happened trying to delete user-anayltics ${(err as Error).message}`);
});

但我总是得到 An Error happened trying to delete user-anayltics Request failed with status code 403 Forbidden

好吧,经过一些痛苦而漫长的日子(实际上花了我 20 多个小时),我已经想出了如何实现这个请求。这是步骤指南的步骤:

第 1 步 - 所需的依赖项

要向 google 发送 post 请求,我们需要一个 http-client-library。我选择了“ky”,所以我们需要先安装它:

npm install ky

此外,我们需要创建或拥有 oAuth2 令牌,否则 post 请求将被拒绝并显示“错误 403”。要创建我们自己的 oAuth 令牌,我们需要另一个依赖项:

npm install @googleapis/docs

第 2 步 - 需要 Google 属性 ID

根据您的请求,Google 需要知道您的目标是哪个 属性-id / 项目(稍后应该删除用户分析数据)。要获得此 属性-id,我们需要通过 Firebase 登录 GCP(不是“真正的”GCP,而是通过 Firebase 的那个)。

为此,进入您的“console.firebase.google.com”→Select您的项目→分析仪表板→“在Google分析中查看更多信息(右上角的按钮)”

将“属性-id”写入搜索字段,然后将其保存在某处(我们稍后需要它)

第 3 步 - 创建客户端密码

第三步是创建一个服务帐户,稍后我们会将其添加到我们的函数文件夹中,以创建我们的 oAuthClient(别担心,您会明白我的意思的稍后一点)

创建新的service.json,通过“https://cloud.google.com/”登录google云平台,然后按照图片操作:

第一个:

第二个:

第三名:

第四名:

第五

第 4 步 - 下载 JSON

创建“oAuth-Deleter 服务帐户”后,我们需要手动下载所需的 JSON,以便将其粘贴到我们的函数文件夹中。

为此,select“服务帐户”下的“oauth-deleter@your-domain.iam.gserviceaccount.com”

然后点击“密钥”和“添加密钥”,它会自动为您下载一个服务-json (SELECT 密钥类型 → JSON → 创建).

第 5 步 - 将 JSON 文件粘贴到您的函数文件夹中

要稍微放松一下心情,这是一个简单的步骤。将下载的 JSON- 文件粘贴到您的函数文件夹中。

第 6 步 - 授予对我们新创建的 oAuth-Delelter-Account 的访问权限

创建服务帐户并在普通 GCP 中授予它访问权限对于 Google 来说是不够的,因此我们还必须在我们的 Firebase 项目中授予它访问权限。为此,返回“通过 Firebase 的 GCP(参见步骤 2)”→ 单击“设置”→“帐户的用户访问权限”→单击“加号”

然后点击“添加用户”并将我们之前复制的电子邮件写入电子邮件字段(步骤 3 中的电子邮件,图片第四“服务帐户 ID”)。在我们的例子中,它是“oAuth-Deleter@你的-domain.iam.gserviceaccount.com”。此外,它需要管理员权限:

第 6 步 - 代码

现在,经过这百万个不必要但必要的步骤后,我们进入了最后一部分。该死的代码。我用“compilerOptions”→“module”:“esnext”,“target”:“esnext”用打字稿写了这个。但我相信你足够聪明,可以在完成这么多步骤后更改代码:)

import admin from "firebase-admin";
import functions from "firebase-functions";
import ky from "ky";
import docs from "@googleapis/docs";
import { UserRecord } from "firebase-functions/v1/auth";

export const dbUserOnDeleted = functions.
   .auth
   .user()
   .onDelete((user) => doOnDeletedUser(user))

    ----------------------------

export asnc function doOnDeletedUser/user: UserRecord) {
   try {
       const googleDeletionURL = "https://www.googleapis.com/analytics/v3/userDeletion/userDeletionRequests:upsert"
       
       // Step 1: Paste propertyID: (See Step 2)
       const copiedPropertyID = "12345678"

       // Step 2: Create oAuthClient
       const oAuthClient = new docs.auth.GoogleAuth({
           keyFile: "NAME-OF-THE-FILE-YOU-COPIED-INTO-YOUR-FUNCTIONS-FOLDER",
           scopes: ["https://www.googleapis.com/auth/analytics.user.deletion"]
       });

       // Step 3: Get user uid you want to delete from user-analytics
       const uid = user.uid

      // Step 4: Generate access token 
      // (this is the reason why we needed the 5 steps before this)
      // yup, a single line of code
      const accessToken = await oAuthClient.getAccessToken() as string;

      // Step 5: Make the request to google and delete the user
      return ky.post(googleDeletionURL, {
          body: JSON.stringify({
              kind: "analytics#userDeletionRequest",
              id: {
                 type: "USER_ID",
                 userid: uid
              },
              propertyId: copiedPropertyID
          }),
          headers: {
              "Authorization": "Bearer " + accessToken,
          }
      });

   } catch (err) {
     functions.logger.error(`Something bad happened, ${(err as Error).message)`
   }
}

事后思考

这是我在堆栈溢出时最长的 post,并且可能永远如此。我不得不说,让这个东西开始工作真是太痛苦了。简单地从一个端点删除数据所需的工作量和设置量是荒谬的。 Google,请修复。