使用 python-jose 将 Python 后端从 Gitkit 迁移到 Firebase-Auth 以进行令牌验证

Dan*_*l F 2 python migration jwt firebase-authentication gitkit

在 GitHub 上,一位乐于助人的 Google 开发人员告诉我

要创建用户会话,您的 python 后端服务器只需要一个 JWT 库来验证请求中的 Firebase Auth 令牌(签名和受众)并从令牌负载中提取用户信息。

我在验证令牌时遇到问题。

这就是我所在的地方;为了开始迁移,我按照以下步骤进行:

  1. 我将 Firebase-Auth 添加到 Android 应用程序中,同时应用程序中仍保留有 Gitkit,直到 Firebase-Auth 正常工作。现在我有两个登录按钮,一个用于登录 Firebase,另一个用于“几乎已弃用”的 Gitkit。

  2. 在 firebase.com 上,我将 Google 项目导入到新的 Firebase 项目中,因此用户数据库是相同的。我已经成功在 Android 应用程序中使用 Firebase-Auth,能够以已知用户身份登录,并且可以通过调用 成功检索后端服务器所需的令牌mFirebaseAuth.getCurrentUser().getToken(false).getResult().getToken()。它包含user_id与 GitKit 令牌相同的内容。

现在我正在尝试identity-toolkit-python-clientpython-jose. 由于我目前没有将 Firebase 令牌发送到后端,而仅将 Gitkit 令牌发送到后端,因此我想python-jose在 Gitkit 令牌上测试这个库。

在后端,在调用之前,GitKit.VerifyGitkitToken()我现在打印 和 的结果jose.jwt.get_unverified_header()jose.jwt.get_unverified_claims()以便检查我是否看到了我所期望的结果。结果很好,我能够按照预期查看 Gitkit 令牌的内容。

我的问题来自于验证。我无法用于jose.jwt.decode()验证,因为我不知道需要使用哪个密钥

jose.jwt.decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None)

我知道标题中的算法,并且“aud”字段也存储在声明中,如果有任何帮助的话。

回到工程师的评论

验证 Firebase 身份验证令牌(签名和受众)

我如何利用我现有的信息来做到这一点?我猜受众是声明中的“aud”字段,但如何检查签名?

一旦我删除了服务器上的 Gitkit 依赖项,我将继续迁移。

据我所知,GitKit 库显然对 Google 服务器进行了“RPC”调用以进行验证,但我可能是错的。

那么,Gitkit 令牌验证和 Firebase 令牌验证的关键是什么?

Dan*_*l F 5

可以获取钥匙

对于 Firebase,位于 https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com

对于 Gitkit,请访问 https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys

使用 Google 的oauth2client库使验证变得非常容易。

但如果您想使用python-jose而不是oauth2client,那么您首先需要将 PEM 证书转换为 RSA 公钥更新:此问题已修复,对于 Firebase 现在由库处理,向下滚动到 GitHub 链接的末尾在此评论之前。不确定 Gitkit)。这个公钥就是需要使用的密钥。并且受众不应该JWT header 中提取,而是硬编码到源代码中,其中在 Firebase 中受众是项目 id,在 Gitkit 中它是 OAuth 2.0 客户端 ID 之一,可以在 Google 开发者控制台中找到凭证部分。

JWT 标头中kid的 用于选择适当的证书,该证书将用于获取用于执行验证的密钥。

  # firebase
  # target_audience = "firebase-project-id"
  # certificate_url = 'https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com'

  # gitkit
  target_audience = "123456789-abcdef.apps.googleusercontent.com" # (from developer console, OAuth 2.0 client IDs)
  certificate_url = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys'

  response = urllib.urlopen(certificate_url)
  certs = response.read()
  certs = json.loads(certs)
  print "CERTS", certs
  print ''
  print ''

  # -------------- verify via oauth2client
  from oauth2client import crypt
  crypt.MAX_TOKEN_LIFETIME_SECS = 30 * 86400 # according to https://github.com/google/identity-toolkit-python-client/blob/master/identitytoolkit/gitkitclient.py
  print "VALID TOKEN", crypt.verify_signed_jwt_with_certs(idtoken, certs, target_audience)  
  print ''
  print ''

  # -------------- verify via python-jose
  from jose import jwt
  unverified_header = jwt.get_unverified_header(idtoken)
  print "UNVERIFIED HEADER", unverified_header
  print ''
  print ''
  unverified_claims = jwt.get_unverified_claims(idtoken)
  print "UNVERIFIED CLAIMS", unverified_claims
  print ''
  print ''
  from ssl import PEM_cert_to_DER_cert
  from Crypto.Util.asn1 import DerSequence
  pem = certs[unverified_header['kid']]
  der = PEM_cert_to_DER_cert(pem)
  cert = DerSequence()
  cert.decode(der)
  tbsCertificate = DerSequence()
  tbsCertificate.decode(cert[0])
  rsa_public_key = tbsCertificate[6]
  print "VALID TOKEN", jwt.decode(idtoken, rsa_public_key, algorithms=unverified_header['alg'], audience=target_audience)
Run Code Online (Sandbox Code Playgroud)