最近苹果账号不知道咋的弄出来一个账号密码登陆后需要手机验证码双重认证登陆,很麻烦于是想通过App Store Connect API直连导出财务日志之类的东西。
苹果提供了一套JWT的验证连接方式,关于JWT网上介绍很多在此对细节略过不表。
而完成登陆简单点讲就是需要在发送向指定http地址的get请求头中添加JWT。具体生成JWT的过程如下(前两步)。
1. 生成API key
https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api
登陆itunes connect后按指示点选即可,最后设置好密钥权限后点击下载唯一的私钥文件,文件名默认为"AuthKey_XXXXXXXXXX.p8",其中<xx…x>部分为该密钥ID
2.生成json Web Token
https://developer.apple.com/documentation/appstoreconnectapi/generating_tokens_for_api_requests
JWT包含三部分,最终格式为<header>.<payload>.<sign>,好在python并不需要我们自己去转码,直接按照官网指点构造好各个部分使用pyjwt包自动构造就行了。
下面直接上代码
import time, jwt
# 1. Create the JWT header
header = {
"alg": "ES256",
"kid": "XXXXXXXXXX", # your own key ID
"typ": "JWT"
}
# 2.1 Create the JWT payload
payload = {
"iss": "XXX-XXX-XXX-XXX-XXX",
# 在Store Connect上可以点击复制 iss ID
"exp": int(time.time()) + 60*10,
# token最长有效时间20min,这里设置为10min
"aud": "appstoreconnect-v1"
}
# 2.2 privateKey 直接打开导入
privatekey = open('D:/AuthKey_S93MFC6GNN.p8', 'r').read()
# 3. Sign the JWT
nc = jwt.encode(payload=payload, key=privatekey, algorithm='ES256', headers=header)
运行如下:这里需要注意,苹果采用的ES256编码方式,key是需要分段(\n)的,密钥头尾的"—BEGIN PRIVATE KEY—"也是必须的。之前我一直直接复制privatekey以文本的形式输入,在HS256下正常但是ES256会报错ValueError: Could not deserialize key data。还以为是什么PEM、SSH之类编解码方式的问题折腾了半天,最后受到这篇文章(感谢 http://www.mamicode.com/info-detail-1470498.html )的提醒才想到也许仅仅是格式问题。因此直接使用open的形式打开.p8密钥文件,就没有问题了。
在得到JWT后,苹果给出的示例连接是:
也就是说发送一个带Header的get请求到如上网址,下面用request来写(附curl转request: http://curl.trillworks.com ):
报安全原因的拒绝访问,说明JWT已经生效(如果是JWT有问题会报401)
3. 连接
产生密钥后利用这个密钥去连接App Store Connect API,这里尝试连接的是销售和趋势中的销量( https://developer.apple.com/documentation/appstoreconnectapi/download_sales_and_trends_reports )
# 4. Include the signed JWT in the authorization header of each App Store Connect API request
import requests
str_dtt = '2019-03-10' # 指定想要得到的日期
str_vnd = '00000000' # 你自己的vendorNumber
str_url = "https://api.appstoreconnect.apple.com/v1/salesReports?filter[reportDate]=%s&filter[reportSubType]=SUMMARY&filter[reportType]=SALES&filter[frequency]=WEEKLY&filter[vendorNumber]=%s" % (str_dtt, str_vnd)
# 苹果这个接口有一堆又臭又长的Query string Parameters,简直恶心
# 其中vendorNumber就是供应商编号,在itunesConnect登陆后"付款和财务报告"页左上角可以找到
mdl_rqt = requests.get(
str_url,
headers={
'Content-Type': 'application/a-gzip',
# 增加Content-Type是因为苹果本API返回数据格式为gzip
'Authorization': 'Bearer %s'%str(nc, encoding='utf-8')
# 指定JWT
},
timeout=30
)
# 5. 将get回来的content使用gzip解码
import gzip
print(gzip.decompress(mdl_rqt.content).decode("utf-8"))
不过此API的参数设置有个奇怪的地方,就是当filter[reportSubType]=Detailed的时候,会莫名报filter[vendorNumber]错误···搞不懂。除此以外一切正常如下。
完成。