2

我正在做一个项目,我们将在微服务架构中使用不同的服务,并且我们还想使用一些 Firebase 服务。我正在开发一个身份验证服务器,该服务器将创建自定义 JWT,以用于 Firebase 以及其他 API 项目。

我们希望使用 Firebase Auth SDK 轻松与 FB、Google、Twitter 等集成,但我们需要用更多数据丰富用户的令牌。因此,我的想法是创建一个使用 Firebase Admin SDK 来执行此操作的 Node.JS 身份验证服务器。流程如下:

  1. 用户在客户端使用最喜欢的提供商登录
  2. 如果登录成功,用户会收到来自 Firebase 的 JWT。这被发送到身份验证服务器进行验证
  3. 如果身份验证服务器可以使用管理 SDK 验证令牌,则创建一个包含更多数据的新自定义令牌,并将此新自定义令牌返回给客户端
  4. 让客户端使用新的自定义令牌重新进行身份验证,并将其用于与 Firebase 以及我们的其他 API 项目(主要在 .NET Core 中)进行通信

步骤 1-3 工作正常。尝试验证其他服务上的自定义令牌时会出现问题

TL; DR:这里有两个问题:

  1. 验证使用 Firebase Node.JS Admin SDK 发布的自定义令牌时,我应该使用什么作为公钥?从 Google 公开的 JWK 中提取的密钥,还是从用于签名的私钥中提取的密钥?
  2. 在 JWK 方法的情况下,我应该如何构造带有kid标题的自定义令牌?

首先,我怀疑验证它的正确方法。(请原谅,我在创建 OAuth 流程方面没有经验。)使用的算法是 RS256,所以我应该能够使用公钥来验证令牌。如我所见,有两种方法可以获取此密钥:

  1. 从私钥中提取公钥并使用它进行验证。我可以这样做并在我的身份验证服务器上的测试端点上成功验证,但是我觉得这是不正确的方法
  2. 我认为另一种更正确的方法是使用令牌中的值在我的项目的 Google 的“/.well-known/openid-configuration/”端点上找到 JWK,即

https://securetoken.google.com/[项目 ID]/.well-known/openid-configuration

检索正确(密钥 ID)的指数和模数kid并从中创建公钥。

通过执行从 admin SDK 生成的令牌

admin.auth().createCustomToken(uid, additionalClaims).then(function(customToken)

一些自定义声明看起来像这样:

标题:

{
  "alg": "RS256",
  "typ": "JWT"
}

有效载荷:

{
  "claims": {
    "premiumAccount": true,
    "someRandomInnerObject": {
      "something": "somethingRandom"
    }
  },
  "uid": "<uid for the user>",
  "iat": 1488454663,
  "exp": 1488458263,
  "aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
  "iss": "firebase-adminsdk-le7ge@<PROJECT ID>.iam.gserviceaccount.com",
  "sub": "firebase-adminsdk-le7ge@<PROJECT ID>.iam.gserviceaccount.com"
}

不过,我似乎无法让方法 2 起作用。一个问题是生成的令牌没有 kid 标头,因此不符合 OpenID 规范 (AFAIK),这导致以下两种选择之一:

  1. 使用上面的第一种方法。但是这会导致问题 - 如果我出于某种原因需要撤销或重置身份验证服务器上的私钥,我需要这样做并将更改也部署到所有其他服务上,从而使解决方案的动态性降低且更容易出错.
  2. 使用 jwt.io 中提到的库之一手动生成类似的令牌,并将原始 Firebase ID 令牌中的孩子添加到其标头中。

2号问题:

  • 那么我应该把什么作为 iss、aud 和 sub 呢?与 admin SDK 的值相同吗?如果是这样,那不是“作弊”吗,因为他们不再是发行人?
  • 我已经尝试过了(生成令牌的类似副本,但添加了kid原始令牌的副本),但我似乎无法使用为孩子创建的 PEM 密钥验证生成的令牌。

我做后者的方式是这样的(遵循关于该主题的博客指南):

  1. 转到https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com并检索相关孩子的模数 (n) 和指数 (e)

  2. 使用 lib ( rsa-pem-from-mod-exp )生成公钥

  3. 使用密钥验证使用“官方”jwt lib

    上面的结果是这样的公钥:

    -----BEGIN RSA PUBLIC KEY----- MIIBCgKCAQEAxXpo7ChLMnv1QTovmm9DkAnYgINO1WFBWGAVRt93ajftPpVNcxMT MAQI4Jf06OxFCQib94GyHxKDNOYiweVrHVYH9j/STF+xbQwiPF/8L7+haC2WXMl2 tkTgmslVewWuYwpfm4CoQFV29OVGWCqwEcbCaycWVddm1ykdryXzNTqfzCyrSZdZ k0yoE0Q1GDcuUl/6tjH1gAfzN6c8wPvI2YDhc5gIHm04BcLVVMBXnC0hxgjbJbN4 zg2QafiUpICZzonOUbK6+rrIFGfHpcv8mWG1Awsu5qs33aFu1Qx/4LdMAuEsvX9f EmFZCUS8+trilqJbcsd/AQ9eOZLAB0BdKwIDAQAB -----END RSA PUBLIC KEY--- --

有两件事似乎是错误的。一是密钥与我可以从私钥中提取的密钥不同。另一个是我从私钥中提取的那个有这些注释:

-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----

没有'RSA'。这有关系吗?在任何情况下,它都无法验证。

最后,我是不是完全误解了 OpenID 流程?JWK 是否也是从我需要的私钥生成的,以验证我的 JWT?我是否应该在我的身份验证服务器上公开我自己的 JWK 以供其他服务联系和使用,而不是 Google 的?我对 Firebase Admin SDK 做什么和不做什么有点困惑,我想:-)

我知道这是很多问题,但我认为它们都是相关的。

我在研究中依赖的一些资源(当然除了官方的 admin sdk 文档):

4

1 回答 1

2

在使用自定义令牌重新验证 Firebase 客户端 SDK 后,客户端实际上会使用自定义令牌的声明生成一个新的 ID 令牌。您应该使用此 ID 令牌来验证对不同微服务发出的请求(在此处记录)。所以是的,您的原始 ID 令牌被丢弃,但会在其位置创建一个新的。并且该 ID 令牌将每小时自动刷新一次。因此,您应该能够在user.getToken()需要时调用以获取有效的 ID 令牌。该方法代表您处理所有缓存。

于 2017-03-17T15:02:51.667 回答