REST-запрос к ответу API App Store Connect с «401» | "NOT_AUTHORIZED"

мы запустили приложение для 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.

Удалось ли вам использовать URLRequest и URLSession с токеном?

the Reverend 30.10.2019 20:02
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
2 615
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Ваш токен содержит срок действия

"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 ())

T.Junge 21.12.2018 18:00

У меня была аналогичная проблема, и я решил ее таким образом (я разместил свой ответ здесь): stackoverflow.com/a/56590980/2101576

Nah 14.06.2019 05:24

Во-первых, не открывайте файлы без контекстных менеджеров. Эта строка:

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

должно быть:

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

Это избавит вас от многих проблем с незакрытыми файлами в будущем.

Затем проверьте, какой токен вы прочитали из файла. Это правильно?

Следующая проблема, которую я вижу, - это временная метка. «Срок действия токена в эпоху Unix»; Думаю, вы указываете это за миллисекунды.

Привет @witold komorowski на самом деле я тестирую в почтальоне, где я могу найти закрытый ключ

Ramprasath Selvam 15.07.2021 15:36

Вот рабочее решение для меня. Без промедления возвращает ошибку 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, у меня есть все, кроме закрытого ключа, где я могу найти закрытый ключ и как использовать этот ключ в почтальоне?

Ramprasath Selvam 15.07.2021 15:49

Другие вопросы по теме