мы запустили приложение для iOS, и я хочу получить некоторую информацию (например, установки, обновления, обзоры) из App Store Connect API.
Я создаю веб-токен JSON, как описано в официальной документации Apple: Ссылка на сайт
После этого делаю запрос с токеном в заголовке. Теперь я получаю «401» | 'NOT_AUTHORIZED' каждый раз в качестве ответа, см. Следующую картинку: REST ответ
В следующих фрагментах вы можете увидеть мой код на 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'
Даже если я декодирую первые две части JWT через Base64, я получаю правильный Заголовок (он также содержит правильный алгоритм кодирования: 'alg': 'ES256') и Требовать:
from jose.utils import base64url_decode
print(base64url_decode(b'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlhYWFhYWFhYWFgifQ'))
print(base64url_decode(b'eyJpc3MiOiJYWFhYWFhYWC1YWFhYLVhYWFgtWFhYWC1YWFhYWFhYWFhYWFgiLCJleHAiOjE1NDUzOTc1MTQ1ODAsImF1ZCI6ImFwcHN0b3JlY29ubmVjdC12MSJ9'))
Смотрите следующую картинку: Выходное декодирование Base64
Итак, теперь, когда я думаю, что 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()
И теперь мы видим мою проблему, смотрите картинку: Заголовок | REST ответ
Обратите внимание, что для примера я скрыл KEY_ID, ISSUER_ID и PRIVATE_KEY.






Ваш токен содержит срок действия
"exp": 1545397514580,
что равняется 12 сентября 50941 года.
Когда я удаляю последние три цифры
"exp": 1545397514,
Я получаю 21 декабря 2018 года что имеет гораздо больше смысла.
Измените эту строку
TIMESTAMP = int( (datetime.now() - timedelta(minutes = 45)).timestamp() * 1000)
к
TIMESTAMP = int( (datetime.now() - timedelta(minutes = 45)).timestamp())
exp - метка времени, которая определяется в секундах с 01.01.1970 00:00 См. Также здесь
Большое спасибо, это работает, когда я пишу следующую строку: TIMESTAMP = int ((datetime.now () + timedelta (minutes = 15)). Timestamp ())
У меня была аналогичная проблема, и я решил ее таким образом (я разместил свой ответ здесь): stackoverflow.com/a/56590980/2101576
Во-первых, не открывайте файлы без контекстных менеджеров. Эта строка:
PRIVATE_KEY = open('AuthKey_XXXXXXXXXX.p8', 'r').read()
должно быть:
with open('AuthKey_XXXXXXXXXX.p8', 'r') as f:
PRIVATE_KEY = f.read()
Это избавит вас от многих проблем с незакрытыми файлами в будущем.
Затем проверьте, какой токен вы прочитали из файла. Это правильно?
Следующая проблема, которую я вижу, - это временная метка. «Срок действия токена в эпоху Unix»; Думаю, вы указываете это за миллисекунды.
Привет @witold komorowski на самом деле я тестирую в почтальоне, где я могу найти закрытый ключ
Вот рабочее решение для меня. Без промедления возвращает ошибку 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)
@ Александр Коваленко Я тестирую этот API в POSTMAN, у меня есть все, кроме закрытого ключа, где я могу найти закрытый ключ и как использовать этот ключ в почтальоне?
Удалось ли вам использовать URLRequest и URLSession с токеном?