【问题标题】:How to call Apple Music API and avoid 401如何调用 Apple Music API 并避免 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))

【问题讨论】:

    标签: python windows api jwt apple-musickit


    【解决方案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 ...
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-10-11
          • 2020-07-15
          • 1970-01-01
          • 1970-01-01
          • 2014-11-24
          • 1970-01-01
          • 2020-06-17
          相关资源
          最近更新 更多