关于迁移:将Python后端从Gitkit迁移到具有python-jose的Firebase-Auth,以进行令牌验证

Migrating Python backend from Gitkit to to Firebase-Auth with python-jose for token verification

在GitHub上,一个有用的Google开发人员告诉我,

to create a user session, your python backend server only needs a JWT
library to verify the Firebase Auth token (signature and audience) in
the request and extract the user info from the token payload.

我在验证令牌时遇到麻烦。

我在这里为了开始迁移,我进行了如下操作:

  • 我将Firebase-Auth添加到Android应用程序中,同时在Firebase-Auth工作之前,该应用程序中仍包含Gitkit。现在,我有两个登录按钮,一个用于登录Firebase,另一个用于"几乎已弃用"的Gitkit。

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

  • 现在,我尝试用python-jose替换identity-toolkit-python-client库。由于我当前不将Firebase令牌发送到后端,而仅将Gitkit令牌发送到后端,因此我想在Gitkit令牌上测试此python-jose库。

    在后端,在调用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"字段也存储在声明中。

    回到工程师评论

    verify the Firebase Auth token (signature and audience)

    我该如何利用我掌握的信息呢?我想听众是索赔中的" aud"字段,但是如何检查签名?

    删除服务器上的Gitkit依赖关系后,我将继续进行迁移。

    从我所看到的,GitKit库显然对Google服务器进行了" RPC"调用以进行验证,但是我可能是错的。

    那么,哪一个将是Gitkit令牌验证的关键以及Firebase令牌验证的关键?


    可以获取密钥

    用于Firebase
    https://www.googleapis.com/robot/v1/metadata/x509/[email protected]

    对于Gitkit
    https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys

    使用Googles oauth2client库使验证非常容易。

    但是,如果要使用python-jose而不是oauth2client,则首先需要将PEM证书转换为RSA公钥(更新:此问题已解决,对于Firebase,现在由库处理,向下滚动至 注释前面的GitHub链接的末尾。不确定Gitkit)。 然后,此公共密钥就是需要使用的密钥。 而且受众不应该从JWT标头中提取出来,而应该硬编码到源代码中,在Firebase中,受众是项目ID,而在Gitkit中,受众是OAuth 2.0客户端ID之一,可以在Google Developer Console中找到 凭据部分。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
      # firebase
      # target_audience ="firebase-project-id"
      # certificate_url = 'https://www.googleapis.com/robot/v1/metadata/x509/[email protected]'

      # 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)