是否仍然可以在Firebase 3中对令牌进行服务器端验证?

时间:2016-05-24 08:53:24

标签: firebase firebase-authentication

是否仍然可以在Firebase 3中对令牌进行服务器端验证?

我们使用现有的身份验证系统(使用服务帐户)在运行Golang的服务器上生成自定义令牌(JWT)。 令牌使用

在iOS客户端上使用
FIRAuth.auth()?.signInWithCustomToken(customToken)

直到那里一切正常。但是当我们将客户端令牌传递给从以下位置检索的服务器时:

FIRUser.getTokenWithCompletion({ token, error in ..})

我们无法验证它。 JWT令牌使用RS256签名,并且有一个我们无法识别的header.kid。服务帐户(用于签署自定义令牌)的公钥不验证客户端令牌。 验证客户端令牌是否需要公钥?

我知道可以使用Java或Javascript中的“verifyIdToken”调用验证客户端令牌,但我们希望能够使用标准JWT库在Golang中执行此操作。

这一切在Firebase 2中运行良好(使用HS256和Firebase秘密)。

2 个答案:

答案 0 :(得分:50)

简短的回答是肯定的。完整的答案是,在大多数情况下,我们现在有一个更合适的工具。所以很大程度上取决于您尝试解决的用例。

新的SDK版本功能更强大,我们在总结功能方面做得不是很好。这似乎是对比可用工具及其用途的好地方,然后我将在最后处理一些第三方(即Go)特定的注释。

使用外部身份验证工具进行客户端身份验证

创建自定义令牌的主要用途是允许用户针对您控制的外部/旧版身份验证机制(例如LDAP服务器)进行身份验证。此处介绍了基本流程:iOSAndroidWeb

基本上,您的服务只需将JWT令牌放入其中并将其传递给客户端。客户端使用您提供的自定义令牌进行验证/身份验证。

对您的特权工作人员进行身份验证

不再需要使用自定义令牌来验证您的服务器进程。这是通过创建服务帐户来完成的,该帐户在Adding Firebase to your Server中逐步介绍。完成后,您将获得包含私钥的JSON文件。

然后,您可以使用serviceAccount中的firebase.initializeApp()属性引用该JSON来包含您的服务帐户凭据,然后您就可以了!该文档记录为here,看起来像这样(参见Java版链接):

var firebase = require("firebase");

// Initialize the app with a service account, granting admin privileges
firebase.initializeApp({
  databaseURL: "https://databaseName.firebaseio.com",
  serviceAccount: "./serviceAccountCredentials.json"
});

模拟用户或限制来自服务器进程的访问

模拟用户或限制来自服务器进程的访问(强烈推荐)是相当简单的。你真的不需要为此制作自定义令牌了。

这只需要将databaseAuthVariableOverride添加到您对database.initializeApp()的调用中:

firebase.initializeApp({
  databaseURL: "https://databaseName.firebaseio.com",
  serviceAccount: "./serviceAccountCredentials.json",
  databaseAuthVariableOverride: {
    uid: "my-service-worker-or-user-uid"
  }
});

通过安全验证客户身份

首先,如果您使用的是Firebase数据库,通常可以避免处理服务器端验证,方法是让客户端写入数据库并使用安全规则验证其身份。如果您的服务器在需要身份验证的路径上进行侦听,那么这已经解决,而服务器上没有任何特殊安全性。

通过将其建模为事件队列,它可以创建一个简单,模块化和可伸缩的服务器工作策略。有关一些出色的Node.js工具,请参阅firebase-queue。它supports 3.x

验证服务器上的客户端ID令牌

如果您没有使用实时数据库并且需要接收客户端令牌(例如通过REST调用)并验证它们是否有效,您可以按照{{3}所述使用verifyIdToken()来执行此操作}。这看起来如下:

auth.verifyIdToken(idToken).then(function(decodedToken) {
  var uid = decodedToken.sub;
});

如果您希望以该用户身份进行身份验证以写入数据库并强制实施安全性,则可以使用上面的模拟用户部分。换句话说,调用initializeApp()并将databaseAuthVariableOverride设置为相应的uid。

请注意,如果您尝试多次调用initializeApp()并遇到类似于以下内容的错误:Error: Firebase App named '[DEFAULT]' already exists.您可以通过向initializeApp()调用添加第二个参数来初始化多个应用上下文(例如database.initializeApp({...}, 'asUser'+uid))然后使用firebase.database('asUser'+uid)。ref(...)引用该应用实例。要详细了解如何使用多个应用实例here

上面链接中提供的Java代码。转到下面介绍的其他第三方解决方案。

创建用于REST API的令牌

Michael Bleigh介绍了这个场景look here并且值得一些代表来解决这个问题。

通过REST创建令牌或验证它们

这不受支持。遗憾。

Golang和其他人:更多内容

我们正在开发Go令牌铸造和验证库。我们也将很快为此添加Python工具。没有发布日期或球场。与此同时,如果您想在不使用官方Firebase Node.js或Java库(具有内置验证方法)的情况下验证客户端ID令牌,则需要确保ID令牌(即JWT)符合以下条件:

  • 其解码标头的alg(算法)声明等于"RS256"
  • 其解码的有效负载的aud(受众群体)声明等同于您的Firebase项目ID。
  • 其解码的有效负载的iss(发行人)声明等于"https://securetoken.google.com/<projectId>"
  • 其解码的有效负载具有非空字符串sub(主题)声明。请注意,这是Firebase用户的uid
  • 其已解码的标头具有kid(密钥ID)声明,该声明对应于https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com中列出的公钥之一。
  • 您还需要使用JWT库来验证带有公钥的令牌,以证明令牌已使用公钥进行签名。相应的私钥。

对于Go,您似乎可以使用here来解码和验证客户端ID令牌。

答案 1 :(得分:0)

好的firebase不允许验证custom tokens他们所做的是允许在用户使用自定义令牌登录后验证id tokens生成的内容。 就像我的情况一样,如果您将firebase自定义令牌传递给其他服务以使用您的后端进行身份验证,那么自定义令牌验证就会在您身上! 此外,Google服务帐户X509 cert格式不正确。它有这些\n (new line)分隔符,不会被文本编辑器中的新行替换(我使用vim)。因此我所做的是:

  val factory = CertificateFactory.getInstance("X.509")
  val certificateFile = this.getClass.getResourceAsStream(Play.current.configuration.getString("firebase.certificate").get)
  val publicKey = factory.generateCertificate(certificateFile).asInstanceOf[X509Certificate].getPublicKey
  val claimBody = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(compactJws).getBody
  1. 从设置firebase时下载的json中指定的Google服务帐户链接获取证书
  2. 用新行手动替换\n
  3. 获取JWT库。我使用这个很棒的库来验证Java JWT
  4. 阅读证书并提取公钥。
  5. 使用公钥验证令牌
  6. 确保您有另一个api来刷新令牌,因为它只有一个小时有效
  7. 希望有所帮助!