Как вызвать Apple Music API и избежать ошибки 401

Я постоянно получаю ошибку 401 при попытке вызвать Apple Music API. Я использую машину с Windows, и ниже приведен код Python для нее.


import datetime
import jwt

secret = """-----BEGIN PRIVATE KEY-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxx
-----END PRIVATE KEY-----"""

kid = 'ABCDEFGHI'
teamId = 'JKLMNOPQRS'
alg = 'ES256'

headers = {
    'alg': alg,
    'kid': kid
}

payload = {
    'iss': teamId,
    'iat': 1518033023,
    'exp': 1518290267
}

if __name__ == '__main__':
    '''Create an auth token'''
    token = jwt.encode(payload, secret, algorithm=alg, headers=headers)

print '----CURL----'
print ("curl -v -H 'Authorization: Bearer %s' \"https://api.music.apple.com/v1/catalog/us/playlists/pl.14362d3dfe4b41f7878939782647e0ba\" " % (token))

person MSTR Prime    schedule 07.02.2018    source источник


Ответы (4)


У меня была такая же проблема с оператором форматирования строки. Поэтому используйте это:

"""Create an auth token"""
token = jwt.encode(payload, secret, algorithm=alg, headers=headers)
token_str = token.decode('utf-8')  # converts bytes to string

url = "https://api.music.apple.com/v1/catalog/us/playlists/pl.14362d3dfe4b41f7878939782647e0ba" 

print("curl -v -H 'Authorization: Bearer" + token_str + "\"" + url + "\"")

Далее: я предполагаю, что вы хотите получить прямой доступ к данным. Для этого вы можете использовать запросы библиотека:

import requests
request_obj = requests.get(url, headers={'Authorization': "Bearer " + token_str})
json_dict = request_obj.json()

Ваше здоровье!

person sanwall    schedule 12.02.2018
comment
Ссылка на библиотеку запросов не работает, вы можете обновить ее! - person Aditya Ahuja; 19.03.2020

Добавление к ответу sanwall - это работает для меня (Python 3.x):

from datetime import datetime
import jwt
import requests
import json

secret_key = '''-----BEGIN PRIVATE KEY-----
... your secret key here ...
-----END PRIVATE KEY-----'''

key_id  = '0123456789' # <-- your key id here
team_id = '0123456789' # <-- your team id here
alg     = 'ES256'
iat     = int(datetime.utcnow().strftime("%s")) # set issued at to now
exp     = iat + 86400 # add e.g. 24h from now for expiration (24 * 3600secs == 86400)

payload = {
    'iss': team_id,
    'iat': iat,
    'exp': exp
}

headers = {
    'alg': alg,
    'kid': key_id
}

token = jwt.encode(payload, secret_key, algorithm=alg, headers=headers)
token_str = token.decode('utf-8')

url = "https://api.music.apple.com/v1/catalog/us/songs/203709340"
print (f"curl -v -H 'Authorization: Bearer {token_str}' {url}")

Или используйте запросы со сгенерированной строкой токена:

res = requests.get(url, headers={'Authorization': "Bearer " + token_str})
result = json.loads(res.text)

Распечатка:

{'data': [{'id': '203709340', 'type': 'songs', 'href': '/v1/catalog/us/songs/203709340', ... etc ...
person petezurich    schedule 17.03.2019

У меня была та же проблема. Для меня в моем файле .p8 ключ был в нескольких строках, хотя он должен был быть только в одной:

-----BEGIN PRIVATE KEY-----
notarealkey5GSM49AgEGCCqGSM49AwEHBHkwdwIBAQQguWRXMHYkuFImkMGByqEPT
jaXQyO0WK1BjYpuDxIgNQ5nHRRFCuUOi8mgCgYIKoZIzj0DAQehcp0+Z+jwRANCAA
RCBFg8fL08QS36Fb8HmY+eFrDWMO00w5unCo5n8VyLhvttIZeByXlVsJrK/L3f/
F2wYmZme
-----END PRIVATE KEY-----

vs:

-----BEGIN PRIVATE KEY-----
asdfg1rty5GSM49AgEGCCqGSM49AwEHBHkwdwI...
-----END PRIVATE KEY-----
person barbecu    schedule 22.03.2020

Apple Music API требует и токен разработчика, и токен пользователя. Хотя вопрос касается Python, этот ответ предназначен для быстрых разработчиков, которые столкнутся с этой проблемой в будущем.

Например,

static func addPlaylistPathURLString(developerToken: String, userToken: String) -> URLRequest {
         var urlComponents = URLComponents()
         urlComponents.scheme = "https"
         urlComponents.host = "api.music.apple.com"
         urlComponents.path = "/v1/me/library/playlists/

         // Create and configure the `URLRequest`.

         var urlRequest = URLRequest(url: urlComponents.url!)
         urlRequest.httpMethod = "GET"

         urlRequest.addValue("Bearer \(developerToken)", forHTTPHeaderField: "Authorization")
         urlRequest.addValue(userToken, forHTTPHeaderField: "Music-User-Token")

         return urlRequest
     }

     func addPlaylistPathURLString(with developertoken: String, userToken: String, completion: @escaping CatalogSearchCompletionHandler) {

 guard let developerToken = refreshDeveloperToken() // its developer token 
else {
           fatalError("Developer Token not configured. See README for more details.")
             }
            let urlRequest = AppleMusicRequestFactory.addPlaylistPathURLString(developerToken: developerToken, userToken: userToken)
            print(urlRequest)

             let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in
                 guard error == nil, let urlResponse = response as? HTTPURLResponse, urlResponse.statusCode == 200 else {
                     completion([], error)

                     return
                 }
                 guard
                    let data = data,
                   let json = String(data: data, encoding: .utf8)

                else { return }
                print("json:", json)
               do {
                    // do your stuffs---

                  } catch {

                 print("An error occurred: \(error.localizedDescription)")
                 }
             }

             task.resume()

        }

Что касается того, как получить токен пользователя из токена разработчика,

func requestUserToken() {
        guard let developerToken = appleMusicManager.refreshDeveloperToken() // its developer token 
   else {
            return
        }

        if SKCloudServiceController.authorizationStatus() == .authorized {

            let completionHandler: (String?, Error?) -> Void = { [weak self] (token, error) in
                guard error == nil else {
                    print("An error occurred when requesting user token: \(error!.localizedDescription)")
                    return
                }

                guard let token = token else {
                    print("Unexpected value from SKCloudServiceController for user token.")
                    return
                }

                self?.userToken = token
                print(token)

                /// Store the Music User Token for future use in your application.
                let userDefaults = UserDefaults.standard

                userDefaults.set(token, forKey: AuthorizationManager.userTokenUserDefaultsKey)
                userDefaults.synchronize()

                if self?.cloudServiceStorefrontCountryCode == "" {
                    self?.requestStorefrontCountryCode()
                }

                NotificationCenter.default.post(name: AuthorizationManager.cloudServiceDidUpdateNotification, object: nil)
            }

            if #available(iOS 11.0, *) {
                cloudServiceController.requestUserToken(forDeveloperToken: developerToken, completionHandler: completionHandler)
            } else {
                cloudServiceController.requestPersonalizationToken(forClientToken: developerToken, withCompletionHandler: completionHandler)
            }
        }
    }
person AzeTech    schedule 26.03.2020