Firebase服务帐户生成身份验证令牌,以供客户端与Google Apps脚本一起使用

时间:2019-02-09 06:59:50

标签: firebase google-apps-script

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

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

//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获取身份验证令牌。我 am 能够使用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。

1 个答案:

答案 0 :(得分:2)

好吧,所以经过漫长的一天,我想通了。我将列出我最终用于库的内容以及问题所在(请参阅第三个库)。主要问题是教程已过时,并且没有多少人在应用程序脚本中使用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自定义令牌登录的用户!我遇到了一些有类似问题的人,希望对您有所帮助。