如何调用 Apple Music API 并避免 401
Posted
技术标签:
【中文标题】如何调用 Apple Music API 并避免 401【英文标题】:How to call Apple Music API and avoid 401 【发布时间】:2018-07-18 08:49:36 【问题描述】:我在尝试调用 Apple Music API 时不断收到 401 错误。我使用的是 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))
【问题讨论】:
【参考方案1】:Apple Music API 需要开发者令牌和用户令牌。虽然问题是关于 python 的,但这个答案是为将来遇到这个问题的 swift 开发人员准备的。
例如,
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)
【讨论】:
【参考方案2】:我遇到了同样的问题,对我来说,我的 .p8 文件在多行上却有键:
-----BEGIN PRIVATE KEY-----
notarealkey5GSM49AgEGCCqGSM49AwEHBHkwdwIBAQQguWRXMHYkuFImkMGByqEPT
jaXQyO0WK1BjYpuDxIgNQ5nHRRFCuUOi8mgCgYIKoZIzj0DAQehcp0+Z+jwRANCAA
RCBFg8fL08QS36Fb8HmY+eFrDWMO00w5unCo5n8VyLhvttIZeByXlVsJrK/L3f/
F2wYmZme
-----END PRIVATE KEY-----
对比:
-----BEGIN PRIVATE KEY-----
asdfg1rty5GSM49AgEGCCqGSM49AwEHBHkwdwI...
-----END PRIVATE KEY-----
【讨论】:
【参考方案3】:字符串格式化操作符也有同样的问题。因此使用这个:
"""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 + "\"")
进一步:我假设您想直接访问数据。为此,您可以使用requests 库:
import requests
request_obj = requests.get(url, headers='Authorization': "Bearer " + token_str)
json_dict = request_obj.json()
干杯!
【讨论】:
请求库的链接失效了能不能更新一下!【参考方案4】:添加到 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 ...
【讨论】:
以上是关于如何调用 Apple Music API 并避免 401的主要内容,如果未能解决你的问题,请参考以下文章
如何在我自己的应用程序中实现 Apple Music 中的迷你播放器?
是否还有办法在 iTunes Store 而不是 Apple Music 中打开 iTunes 搜索 API trackViewUrl?