【问题标题】:REST request to App Store Connect API response with '401' | 'NOT_AUTHORIZED'对 App Store Connect API 的 REST 请求以“401”响应 | '未经授权'
【发布时间】:2019-05-22 00:11:56
【问题描述】:

我们启动了一个 iOS 应用,我想从 App Store Connect API 获取一些信息(例如安装、更新、评论)。

我按照 Apple 官方文档中的描述创建了一个 JSON Web Token:Link

之后,我使用标头中的令牌发出请求。现在我得到一个'401' | 'NOT_AUTHORIZED' 每次作为答案,见下图: REST Response

在下面的sn-ps中可以看到我的python代码(我试过用Python和R解决,但结果总是一样)。

首先,我创建一个 JWT:

从日期时间导入日期时间,时间增量 从何塞进口 jwt,jws 进口ecdsa KEY_ID = "XXXXXXXXX" ISSUER_ID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" PRIVATE_KEY = open('AuthKey_XXXXXXXXXX.p8', 'r').read() TIMESTAMP = int((datetime.now() - timedelta(minutes = 45)).timestamp() * 1000) 声明 = {"iss" : ISSUER_ID, “exp”:时间戳, “aud”:“appstoreconnect-v1”} 标头 = { “alg”:“ES256”, “孩子”:KEY_ID, “典型”:“智威汤逊” } # 创建 JWT 编码= jwt.encode(声明,PRIVATE_KEY,算法='ES256',标头=标头)

现在当我打印 encoded 时,我开始关注 JWT(看起来对我有效):

'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlhYWFhYWFhYWFgifQ.eyJpc3MiOiJYWFhYWFhYWC1YWFhYLVhYWFgtWFhYWC1YWFhYWFhYWFhYWFgiLCJleHAiOjE1NDUzOTc1MTQ1ODAsImF1ZCI6ImFwcHN0b3JlY29ubmVjdC12MSJ9.eTl6iaAW-Gp67FNmITrWCpLTtJzVdLYXIl5_KKgqaNgzwyGo7npBOBo9_u5PtLNnssQFEwJWbPND-6Ww5ACgEg'

即使我通过 Base64 解码 JWT 的前两部分,我也会得到正确的 Header(它还包含正确的编码算法:'alg': 'ES256')和 声明:

从 jose.utils 导入 base64url_decode 打印(base64url_decode(b'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlhYWFhYWFhYWFgifQ')) 打印(base64url_decode(b'eyJpc3MiOiJYWFhYWFhYWC1YWFhYLVhYWFgtWFhYWC1YWFhYWFhYWFhYWFgiLCJleHAiOjE1NDUzOTc1MTQ1ODAsImF1ZCI6ImFwcHN0b3JlY29ubmVjdC12MSJ9'))

见下图:Output Base64 Decoding

所以现在,我认为 JWT-Object 已准备就绪,我将请求发送到 API:

导入请求 JWT = 'Bearer' + 编码 URL = 'https://api.appstoreconnect.apple.com/v1/apps' HEAD = {'授权':JWT} 打印(头部) R = requests.get(URL, headers=HEAD) R.json()

现在我们可以看到我的问题了,看图:Header | REST Response

请注意,我已经隐藏了示例的 KEY_ID、ISSUER_ID 和 PRIVATE_KEY。

【问题讨论】:

  • 你能用令牌使用 URLRequest 和 URLSession 吗?

标签: python ios jwt


【解决方案1】:

您的令牌包含到期时间

“exp”:1545397514580,

等于 50941 年 9 月 12 日。

当我删除最后三位时

“exp”:1545397514,

我得到了 2018 年 12 月 21 日 这更有意义。

改变那一行

TIMESTAMP = int( (datetime.now() - timedelta(minutes = 45)).timestamp() * 1000)

到

TIMESTAMP = int( (datetime.now() - timedelta(minutes = 45)).timestamp())

exp 是一个时间戳,定义为自 01.01.1970 00:00 以来的秒数 另见here

【讨论】:

  • 非常感谢,当我写下以下行时它可以工作: TIMESTAMP = int( (datetime.now() + timedelta(minutes = 15)).timestamp())
  • 我有类似的问题,我通过这种方式解决了(我在这里发布了我的答案):stackoverflow.com/a/56590980/2101576
【解决方案2】:

首先,请不要在没有上下文管理器的情况下打开文件。这个字符串:

PRIVATE_KEY = open('AuthKey_XXXXXXXXXX.p8', 'r').read()

应该是:

with open('AuthKey_XXXXXXXXXX.p8', 'r') as f:
    PRIVATE_KEY = f.read()

它使您免于将来出现许多未关闭文件的问题。

然后,检查您从文件中读取的令牌。对吗?

我看到的下一个问题是时间戳。 "令牌的过期时间,以 Unix 纪元时间为单位;"我猜你以毫秒为单位提供它。

【讨论】:

  • 嗨@witold komorowski 实际上我正在邮递员中进行测试,在那里我可以找到私钥
【解决方案3】:

这是适合我的解决方案。立即返回 401 错误

KEY_ID = "xxxxx"
ISSUER_ID = "xxxxx"
EXPIRATION_TIME = int(round(time.time() + (20.0 * 60.0))) # 20 minutes timestamp
PATH_TO_KEY = '../credentials/AuthKey_xxxxx.p8'
with open(PATH_TO_KEY, 'r') as f:
    PRIVATE_KEY = f.read()

header = {
    "alg": "ES256",
    "kid": KEY_ID,
    "typ": "JWT"
}

payload = {
    "iss": ISSUER_ID,
    "exp": EXPIRATION_TIME,
    "aud": "appstoreconnect-v1"
}

# Create the JWT
token = jwt.encode(header, payload, PRIVATE_KEY)
JWT = 'Bearer ' + token.decode()
HEAD = {'Authorization': JWT}

# Without delay I got 401 error
time.sleep(5)

URL = 'https://api.appstoreconnect.apple.com/v1/apps';
r = requests.get(URL, params={'limit': 200}, headers=HEAD)

【讨论】:

  • @Oleksandt Kovalenko 我正在 POSTMAN 中测试这个 API,我得到了所有期望的私钥,我可以在哪里找到私钥以及如何在 postman 中使用这个密钥?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多