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

Is it still possible to do server side verification of tokens in Firebase 3?

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

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

FIRAuth.auth()?.signInWithCustomToken(customToken)

在那之前一切正常。但是当我们将客户端令牌传递给从以下检索的服务器时:

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

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

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

这在 Firebase 2 中一切正常(使用 HS256 和 Firebase 秘密)。

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

新版本的SDK功能强大了很多,功能总结的还不够完善。这似乎是对比可用工具及其用途的好地方,然后我将在最后添加一些 third-party(即 Go)特定注释。

使用外部认证工具进行客户端认证

创建自定义令牌的主要用途是允许用户根据您控制的 external/legacy 身份验证机制进行身份验证,例如您的 LDAP 服务器。此处介绍了基本过程:iOS, Android, Web.

本质上,您的服务只是生成 JWT 令牌并将其传递给客户端。客户端使用您提供的自定义令牌执行 verification/authentication。

正在验证您的特权员工

不再需要使用自定义令牌来验证您的服务器进程。这是通过创建一个服务帐户来完成的,Adding Firebase to your Server 中涵盖了 step-by-step。完成后,您将得到一个包含私钥的 JSON 文件。

然后,您通过使用 firebase.initializeApp() 中的 serviceAccount 属性引用 JSON 来包含您的服务帐户凭据,您就成功了!记录在案 here 看起来像这样(参见 link 的 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 数据库,通常可以避免处理 server-side 验证,方法是让您的客户端写入数据库并使用安全规则来验证其身份。如果您的服务器侦听需要身份验证才能写入的路径,那么这已经在服务器上没有任何特殊安全性的情况下得到解决。

通过将其建模为事件 queue,它创建了一个简单、模块化且可扩展的服务器工作者策略。参见 firebase-queue for some great Node.js tools. It supports 3.x

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

如果您没有使用实时数据库并且需要接收客户端令牌(例如通过 REST 调用)并验证它们是否有效,您可以使用 verifyIdToken() 来实现 here.这看起来像下面这样:

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(...) 引用该应用程序实例。要阅读有关使用多个应用程序实例的更多信息,look here.

Java 代码可在上面的 link 中找到。 Go 和下面介绍的其他第三方解决方案。

创建用于 REST 的令牌 API

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

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

这是不支持的。对不起。

Golang 和其他人:还有更多内容

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

  • 它的解码 header 有一个 alg(算法)声明等于 "RS256"
  • 其解码后的负载有一个 aud(受众)声明等于您的 Firebase 项目 ID。
  • 它的解码有效载荷有一个 iss(发行者)声明等于 "https://securetoken.google.com/<projectId>"
  • 它的解码有效负载有一个 non-empty 字符串 sub(主题)声明。请注意,这是该 Firebase 用户的 uid
  • 它的解码 header 有一个 kid(密钥 ID)声明对应于 https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com 中列出的 public 密钥之一。
  • 您还需要使用 JWT 库通过 public 密钥验证令牌,以证明令牌是使用 public 密钥的相应私钥签名的。

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

好吧,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. 从 google 服务帐户 link 中获取证书 json 在设置 firebase
  2. 时下载
  3. 手动将 \n 替换为新行
  4. 获取 JWT 库。我用这个很棒的库来做验证 Java JWT
  5. 读取证书并提取出 public 密钥。
  6. 使用public密钥验证令牌
  7. 确保你有另一个 api 来刷新令牌,因为只有一个小时有效

希望对您有所帮助!