我们启动了一个iOS-App,我想从App Store Connect API中获取一些信息(例如,安装,更新,评论)。
我按照Apple官方文档Link
中的描述创建JSON Web令牌。然后,我用标头中的令牌发出请求。现在我得到一个“ 401” |每次将“ NOT_AUTHORIZED”作为答案,请参见下图: REST Response
在以下代码片段中,您可以看到我的python代码(我试图在Python和R中解决它,但结果始终相同)。
首先,我创建一个JWT:
from datetime import datetime, timedelta from jose import jwt, jws import ecdsa KEY_ID = "XXXXXXXXXX" ISSUER_ID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" PRIVATE_KEY = open('AuthKey_XXXXXXXXXX.p8', 'r').read() TIMESTAMP = int( (datetime.now() - timedelta(minutes = 45)).timestamp() * 1000) claim = {"iss" : ISSUER_ID, "exp" : TIMESTAMP, "aud" : "appstoreconnect-v1"} header = { "alg": "ES256", "kid": KEY_ID, "typ": "JWT" } # Create the JWT encoded = jwt.encode(claim, PRIVATE_KEY, algorithm='ES256', headers=header)
现在,当我打印编码的时,我将遵循以下JWT(对我来说看起来很有效):
'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlhYWFhYWFhYWFgifQ.eyJpc3MiOiJYWFhYWFhYWC1YWFhYLVhYWFgtWFhYWC1YWFhYWFhYWFhYWFgiLCJleHAiOjE1NDUzOTc1MTQ1ODAsImF1ZCI6ImFwcHN0b3JlY29ubmVjdC12MSJ9.eTl6iaAW-Gp67FNmITrWCpLTtJzVdLYXIl5_KKgqaNgzwyGo7npBOBo9_u5PtLNnssQFEwJWbPND-6Ww5ACgEg'
即使我通过Base64解码了JWT的前两个部分,我也得到了正确的 Header (它还包含正确的编码算法:'alg':'ES256')和索赔:
from jose.utils import base64url_decode print(base64url_decode(b'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlhYWFhYWFhYWFgifQ')) print(base64url_decode(b'eyJpc3MiOiJYWFhYWFhYWC1YWFhYLVhYWFgtWFhYWC1YWFhYWFhYWFhYWFgiLCJleHAiOjE1NDUzOTc1MTQ1ODAsImF1ZCI6ImFwcHN0b3JlY29ubmVjdC12MSJ9'))
请参见下图:Output Base64 Decoding
现在,我认为JWT对象已经准备好了,我将请求发送到API:
import requests JWT = 'Bearer ' + encoded URL = 'https://api.appstoreconnect.apple.com/v1/apps' HEAD = {'Authorization': JWT} print(HEAD) R = requests.get(URL, headers=HEAD) R.json()
现在我们可以看到我的问题,请参见图片:Header | REST Response
请注意,对于示例,我已经隐藏了 KEY_ID , ISSUER_ID 和 PRIVATE_KEY 。
答案 0 :(得分:0)
您的令牌包含有效时间
“ 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是一个时间戳,定义为自1970年1月1日00:00以来的秒数。 另请参见here
答案 1 :(得分:0)
首先,请不要在没有上下文管理器的情况下打开文件。该字符串:
PRIVATE_KEY = open('AuthKey_XXXXXXXXXX.p8', 'r').read()
应为:
with open('AuthKey_XXXXXXXXXX.p8', 'r') as f:
PRIVATE_KEY = f.read()
它将使您免于以后遇到未关闭文件的许多麻烦。
然后,检查您从文件中读取了什么令牌。正确吗?
我看到的下一个问题是时间戳。 “令牌的到期时间,以Unix纪元时间为单位;”我猜您以毫秒为单位提供它。
答案 2 :(得分:0)
这是对我有用的解决方案。立即返回 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)