Google Apps 脚本上的 Firebase 数据库机密

Firebase Database Secrets on Google Apps Script

所以,首先,我问这个问题是因为我希望有人承认或否认 - 对我来说是一个神话 - 关于 使用或不使用 已弃用的 firebase 数据库机密

这是为什么?那么,在 Firebase 控制台的 Service Accounts 选项卡中,我可以看到:

Databse secrets are currently deprecated ans use a legacy Firebase token generator. Update your source code with the Firebase Admin SDK

但在这个建议之下,我目前可以看到我的密钥。如果实际上已弃用此密钥,为什么这是可能的?

但这个故事,并没有就此结束。如果使用 Google Apps 脚本 (even on officials) 搜索教程,他们使用已弃用的数据库密钥,但您可以阅读以下内容:

Google warns that this authentication method is deprecated. In fact you can still use this method but standard Service Accounts are more secure and are recommended. As Database secrets are easier to use, far from really deprecated and safe enough for most use cases, that's what we will use here.

再说一次,这怎么可能?

我想说我试过了:

function myFunction() {
  var firebaseUrl = "https://myApp.firebaseio.com/";
  var secret = "theKey";
  var database = FirebaseApp.getDatabaseByUrl(firebaseUrl, secret);
  Logger.log(database.getData());
}

它有效,因为我看不到数据。如果秘密存在,为什么? 这让我想到允许使用密钥,即使它已被弃用

有什么意见吗?

所以我 整整一年半后 ,你是对的,那里的信息将 Firebase 与 Apps 脚本结合使用已过时且具有误导性。我弄明白了,正在尝试更新 Whosebug 和教程中的信息。

But this story, does not ends here. If a search for tutorials using Google Apps Script (even on officials), they use the deprecated database secret key, but you can read this...

您在此处添加的 link 实际上是一个名叫 @RomainVialard 的家伙的第 3 方网站。他的东西过去对我很有用。虽然他网站上的教程已经过时,但他创建的库仍然运行良好,并且最近更新了。


问题(服务器端)- 对 OP 问题的回答

所以对于服务器端部分,我使用了 official-ish OAuth2 Library to generate access tokens from a service account with a private key: https://console.firebase.google.com/u/0/project/<YOUR-PROJECT-ID>/settings/serviceaccounts/adminsdk。然后我创建了一个从 oauth2 库中检索令牌的函数:

function getFirebaseService() {  
  return OAuth2.createService('Firebase')
      // Set the endpoint URL.
      .setTokenUrl('https://accounts.google.com/o/oauth2/token')

      // Set the private key and issuer. I stored mine in the PropertiesService... You could just use a variable somewhere.
      .setPrivateKey(fb_PRIVATE_KEY) //Service account private key
      .setIssuer(fb_SERVICE_EMAIL) //Service account email

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getScriptProperties())

      // Set the scopes.
      .setScope('https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/firebase.database');
}

使用此代码,我可以调用 getFirebaseService().getAccessToken() which returns a valid 'admin' or Editor level access可以在 Firebase 调用中使用的 token!我使用 FirebaseApp 库,因为它很简单!

var service = getFirebaseService();
  if (service.hasAccess()) {
    var fb = FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken());
    //Success! Do what ever with Firebase!!

  } else {
    Logger.log("makeToken: " + service.getLastError());
  }

如果需要,您还可以生成客户端身份验证令牌以使用客户端:FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()).createAuthToken(USER_EMAIL);.


另一个常见问题(客户端)

我必须克服的主要问题, was that Firebase Admin SDK has been upgraded to 3.x. If you update the tutorial code to use the 3.x version一切都很好!

// Initialize Firebase
var config = {
  apiKey: "<Web API Key>",
  authDomain: "<Project ID>.firebaseapp.com",
  databaseURL: "https://<DB URL>.firebaseio.com/"
  };

firebase.initializeApp(config);

//userRequestToken is retrieved from server-side Romain's FirebaseApp Library linked above.
firebase.auth().signInWithCustomToken(userRequestToken).catch(function(error) {
    // Handle Errors here.
    console.error("authClient: ", error.code, error.message);
  });

  return {
    uid: firebase.auth().currentUser.uid,
    metadata: {
      lastSignInTime: firebase.auth().currentUser.lastSignInTime
    }
  }; 

好吧,现在一些用户一直在关注 -整整一年后- 在这个问题中(还要考虑 Chris W 的回答),我 post 使用 GSApp 库的方法,即使没有 数据库秘密 :

  1. 安装 GSApp 库。为此,请转到 Resources 选项卡,然后单击 Libraries 并粘贴 libraryId:MJ5317VIFJyKpi9HCkXOfS0MLm9v2IJHf

  2. 创建服务帐户:

    • 在您的开发人员控制台中创建一个新的 API 项目,或使用与您的脚本关联的项目。
    • Select APIs 和 Auth -> Credentials.
    • 单击'Create New Client Id'
    • Select服务帐户并生成新的JSON密钥。
    • 单击'Create Client Id'。 JSON 键将自动下载。
    • 单击左侧菜单中的'APIs'
    • 启用您需要此服务帐户访问的任何 API。
  3. 复制下载的 JSON 密钥文件的内容 并将其粘贴到您的 scripts 属性中 .为此,请转至 File -> Project properties -> Script properties 选项卡。在 属性 字段中键入 service_account (或者你想命名它),并在 Value 字段中粘贴JSON密钥文件的所有内容

  4. 以下面的代码为例:

    function myFunction() {
      var firebaseUrl = "https://YOUR-FIREBASE-PROJECT.firebaseio.com/";
    
      var jsonKey = JSON.parse(PropertiesService.getScriptProperties().getProperty("service_account"));
      var key = jsonKey.private_key;
      var clientEmail = jsonKey.client_email;  
    
      var serverToken = new GSApp.init(key, ['https://www.googleapis.com/auth/firebase.database', 'https://www.googleapis.com/auth/userinfo.email'], clientEmail);
    
      serverToken.addUser(clientEmail).requestToken();
      var token = serverToken.getToken(clientEmail).token;
    
      var dataPath = 'YOUR-FIREBASE-DATA-PATH';
      var options = {};
      var result = UrlFetchApp.fetch( firebaseUrl  + dataPath + '.json' + '?access_token=' + token, options).getContentText();
      var data = JSON.parse(result);
      var keys = Object.keys(data);
    
      var sheetRow = [];
      var entryKeys;
    
      for (index in keys) {
       sheetRow = [];
       entryKeys = Object.keys(data[keys[index]])
       for (i in entryKeys) {
        Logger.log(entryKeys[i]);
       }
      }
    }
    

您从 firebase 获取数据作为 json 对象,这意味着您需要手动检查对象的所有属性 (forEach, map, for ... of)