无法解码 JSON Web 令牌

Posted

技术标签:

【中文标题】无法解码 JSON Web 令牌【英文标题】:A JSON web token could not be decoded 【发布时间】:2019-03-23 19:24:35 【问题描述】:

我正在尝试将 GitHub Apps 示例起始代码从 Ruby 移植到 Python,但在生成所需的 JWT 时遇到了麻烦。 Ruby script 看起来像这样,并且工作正常:

require 'openssl'
require 'jwt'  # https://rubygems.org/gems/jwt

private_pem = File.read(YOUR_PATH_TO_PEM)
private_key = OpenSSL::PKey::RSA.new(private_pem)

payload = 
  iat: Time.now.to_i,
  exp: Time.now.to_i + (10 * 60),
  iss: GITHUB_APP_IDENTIFIER


jwt = JWT.encode(payload, private_key, "RS256")
puts jwt

我的 Python 脚本如下,在针对 GitHub API 使用时会产生 A JSON web token could not be decoded 错误:

import os
import time
import jwt

APP_IDENTIFIER = os.environ["GITHUB_APP_IDENTIFIER"]

with open('./PRIVATE_KEY.pem', 'r') as f:
    PRIVATE_KEY = f.read()

payload = "iat": int(time.time()),
           "exp": int(time.time()) + (10*60),
           "iss": APP_IDENTIFIER

print(jwt.encode(payload, PRIVATE_KEY, algorithm='RS256'))

当我尝试从两个脚本打印私钥时,我发现 Ruby 版本有一个额外的换行符。我尝试将其添加到 Python 脚本中的私钥,但它并没有改变输出。

我最好的猜测是,区别与OpenSSL::PKey::RSA.new 调用有关,但我不确定这对密钥有什么影响。

【问题讨论】:

您可能会发现 jwt.io 上的在线调试器有助于比较两个生成的令牌。声明是否匹配(直到时间戳)?它可以根据您的公钥验证签名吗? 【参考方案1】:

jwt.encode() 将在 Python 3 中返回字节,这可能最终会在发送管道的某处调用 str()。在 Python 3 中对字节对象调用 str() 可能会导致令人惊讶的行为:

>>> a = b'hello'
>>> str(a)
"b'hello'"

在 Python 3 中将字节转换为字符串的正确方法是使用:

>>> a.decode('utf-8')
'hello'

我在jwt.encode 行的末尾添加了对decode 的调用,API 突然解码 JWT 没有问题。

【讨论】:

以上是关于无法解码 JSON Web 令牌的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中解码 JSON Web 令牌

解码 JSON Web 令牌 (Xamarin.Android)

如何在 Swift 中解码 JWT(JSON Web 令牌)令牌?

令牌身份验证失败:“utf-8”编解码器无法解码位置 0 中的字节 0xe4:无效的继续字节

url解码和发布数据后出错

无法解码令牌:令牌###