【问题标题】:Firebase service account to generate authentication token for client-side use with Google Apps ScriptFirebase 服务帐户生成身份验证令牌以供客户端与 Google Apps 脚本一起使用
【发布时间】:2019-07-03 09:07:08
【问题描述】:

我在使用FirebaseApp(第 3 方 API)生成身份验证令牌时遇到困难,该令牌可以传递到侧边栏并由客户端用于登录和访问我的 Firebase 数据库客户端。

我正在尝试使用this tutorial,但如果不使用makeToken() 中的数据库机密(正在折旧),它就无法正常工作。我更喜欢使用this tutorial 中反映的服务帐户。当我查看生成的令牌之间的差异时,前 2 个由“。”分隔。是相同的,最后一个'.'之后的最后一块。是不同的。长度也是一样的。例如:

//Example Generated by Database Secret: TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBv.ZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=.dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2U= 
//Example Generated by Service Account: TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBv.ZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=.IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbml=

我可以生成 OAuth 访问令牌,将其传递给 FirebaseApp 并生成身份验证令牌,但是当它通过客户端并尝试进行身份验证时,我收到错误:Login Failed! Error: INVALID_TOKEN: Failed to validate MAC.

似乎有很多关于如何做到这一点的错误信息和相互矛盾的信息。


我有一个 getFirebaseService() 函数服务器端,它使用 Apps Script 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.
      .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');
}

我有一个makeToken() 函数服务器端,它使用 OAuth 访问令牌从 Firebase 获取身份验证令牌。我能够在服务器端使用service.getAccessToken() OAuth 令牌来访问和存储数据。所以这行得通,我想我的问题是创建一个更具限制性的客户端身份验证令牌。

function makeToken(){ 
  var service = getFirebaseService();
  if (service.hasAccess()) {
    return FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()) //Database Secret Works: "AAslhfi3MYACCESSTOKEN2930hf03ah4th8" but is being depreciated.
                    .createAuthToken(Session.getActiveUser().getEmail());
  } else {
    Logger.log("makeToken: " + service.getLastError());
  }
}

然后在客户端,从侧边栏,我尝试使用从makeToken() 检索到的自定义身份验证令牌进行身份验证。

var userAuthToken;

google.script.run.withSuccessHandler(function (requestAuthToken) {
  userAuthToken = authenticateClient(requestAuthToken)
}).makeToken();

function authenticateClient(userRequestToken) {
  var ref = new Firebase(fb_URL);

  ref.authWithCustomToken(userRequestToken, function (error, authData) {
    if (error) {
      console.log("FB Login Failed!", error); //Error below come from here.
    }
    else {
      console.log("FB Login Succeeded!", authData);      
    }
  });

  return ref.authData.auth; 
}

这导致Login Failed! Error: INVALID_TOKEN: Failed to validate MAC.

编辑: FirebaseApp 是否有可能是 incorrectly generating JWT 身份验证令牌?

Edit2:我认为上述编辑不太可能,因为我尝试使用 GSApp library 并遇到了同样的问题。它似乎只需要折旧的数据库机密,而不是服务帐户 OAuth。

【问题讨论】:

    标签: firebase google-apps-script


    【解决方案1】:

    好吧,经过漫长的一天,我想通了。我将列出我最终用于库的内容以及问题所在(请参阅第三个库)。主要问题本质上是教程已经过时,而且没有很多人在应用脚本中使用 Firebase。

    OAuth2(服务器端) Link

    我不必在这里更改任何内容!它工作正常,从来没有问题。


    FirebaseApp(服务器端) Link

    这是一个不错的库,我坚持使用它,因为它运行良好(一旦我得到它)。我必须对我提到的来自tutorial 的原始代码进行更改。我的代码是这样结束的并且可以工作:

    if (service.hasAccess()) {   
        return FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()) //get OAuth Token
                          .createAuthToken(Session.getEffectiveUser().getEmail(), null, serviceAccount.client_email, serviceAccount.private_key);
      //... Added the null, private key, and service email parameters.
    

    Firebase(客户端) Link

    好的,所以这是我的主要问题所在——我在客户端设置中遵循的tutorial旧的。我必须自己 upgrade the code 才能使用新的 3.x 版本:

    <script src="https://www.gstatic.com/firebasejs/5.8.2/firebase.js"></script>
    
    // Initialize Firebase
    var config = {
      apiKey: "<Web API Key>",
      authDomain: "<Project ID>.firebaseapp.com",
      databaseURL: "https://<DB URL>.firebaseio.com/"
      };
    
    firebase.initializeApp(config);
    

    有了这个firebase 实例,我能够更新我原来的authenticateClient() 方法:

    function authenticateClient(userRequestToken) {
      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
        }
      }; 
    }
    

    就是这样!我现在有一个 firebase 实例,其中有一个通过 JWT 自定义令牌登录的用户!我遇到了一些有类似问题的人,我希望这会有所帮助。

    【讨论】:

    • 如何导入 firebase 脚本?当我在 html 中执行此操作时,我的脚本中未定义 firebase。当我在 gs 脚本中尝试 eval(UrlFetchApp.fetch("gstatic.com/firebasejs/5.9.2/…); 时出现语法错误(我很确定这是因为该脚本与 google apps script node js env 不兼容)。你能详细说明一下吗您是如何实现
    猜你喜欢
    • 1970-01-01
    • 2019-01-10
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多