繁体   English   中英

Python(请求库)ETL:Spotify API“授权代码流”-请求访问令牌问题

[英]Python (requests library) ETL: Spotify API "Authorization Code Flow" - Request Access Token Problem

语境:

作为刷新 ETL 作业的一部分,我正在开展一个辅助项目,将 Spotify API 中的数据提取到 Microsoft SQL 服务器数据库中。 我需要使用“授权代码流”,这样我就可以通过编程方式授权/验证,所以我的表每天都会填充。

我正在为此使用 Python 请求库,如果可能的话,我不想为此创建 Object 面向解决方案(不是我的偏好)。

问题:

身份验证后我无法获取访问令牌。 看看类似的问题,它与这个问题非常相似: Spotify API Authorization Code Flow with Python

我不确定为什么我会收到响应 400(错误请求)。 有人可以在这里建议吗?

代码:

# used to to encode byte string from CLIENT_ID : CLIENT_SECRET, then decode for Authentication Header
import base64

# used to make HTTP requests from Spotify API
import requests

# used to access the environment variables
import os

def request_user_authorization():
    '''
        HTTP GET request to gain access to data (Authorization Code Flow)
        HTTP POST request to send the code and receive an Authorization Token (current issue)

        https://developer.spotify.com/documentation/general/guides/authorization/code-flow/
    '''
    # URLs
    AUTH_URL = 'https://accounts.spotify.com/authorize'
    TOKEN_URL = 'https://accounts.spotify.com/api/token'
    BASE_URL = 'https://api.spotify.com/v1'

    SPOTIFY_URI = 'https://api.spotify.com/v1/me/player/recently-played'

    # sensitive items
    CLIENT_ID = os.environ.get('SPOTIFY_CLIENT_ID_ENV')
    CLIENT_SECRET = os.environ.get('SPOTIFY_CLIENT_SECRET_ENV')

    # make a request to the /authorize endpoint to get an authorization code
    user_authorization_code = requests.get(
        AUTH_URL, {
            'client_id': CLIENT_ID,
            'response_type': 'code',
            'redirect_uri': SPOTIFY_URI,
            'scope':  'user-read-recently-played',
        }
    )

    # Code 200 = "OK"
    print(user_authorization_code)

    #----------------------------------------------------------#
    api_header_string = base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode('ascii'))

    api_headers={
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Basic %s' % api_header_string.decode('ascii')
    }

    api_payload = {
        'grant_type': 'authorization_code',
        'code': user_authorization_code,
        'redirect_uri': SPOTIFY_URI,
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET
    }

  #issue here: 

    # Make a request to the /token endpoint to get an access token
    access_token_request = requests.post(url=TOKEN_URL, data=api_payload, headers=api_headers)
    
    # returns <Response [400]>

    # https://datatracker.ietf.org/doc/draft-ietf-httpbis-semantics/
        # 15.5.1.  400 Bad Request

        #    The _400 (Bad Request)_ status code indicates that the server cannot
        #    or will not process the request due to something that is perceived to
        #    be a client error (e.g., malformed request syntax, invalid request
        #    message framing, or deceptive request routing).

#     print(access_token_request)
    #----------------------------------------------------------#


request_user_authorization()

您似乎误解了授权代码流的工作原理。

这种流程中的redirect_uri由提供者 api(此处为 spotify)用作回调,为您提供授权码。

spotify API 将调用此 url 并带有可用于请求令牌的code参数。

这意味着要使此流程正常工作,您需要一个 web 服务器准备好接收您在代码请求中提供的 uri 上的请求(并在 spotify 开发人员门户上创建应用程序时指定)。 最好将客户端凭据流用于您的用例。

另外,在使用requests.getrequests.post ...

@Speedlulu 你是对的,这就是问题所在。

对于将来阅读此问题的任何人:这是我发布问题后所学到的:

我误解的是数据流,而客户凭证流(仅限于 Spotify 的应用程序)是更好的选择,因为我不需要该程序的“用户”部分。

Spotify 的客户凭证流程文档: https://developer.spotify.com/documentation/general/guides/authorization/client-credentials/

# used to access environment variables securely (sensitive data)
import os

# used to encode strings into bytes and back
import base64

# used to convert JSON data into strings
import json

# endpoint that I'm connecting to on Spotify's servers
token_request_url = "https://accounts.spotify.com/api/token"

CLIENT_ID = os.environ.get('SPOTIFY_CLIENT_ID_ENV')
CLIENT_SECRET = os.environ.get('SPOTIFY_CLIENT_SECRET_ENV')

# encode credentials into bytes, then decode into a string for the HTTP POST request to Spotify to authenticate
BASE64_ENCODED_HEADER_STRING = base64.b64encode(bytes(f"{CLIENT_ID}:{CLIENT_SECRET}", "ISO-8859-1")).decode("ascii")

#initializing dictionaries for HTTP POST request
headers = {}
data = {}

headers['Authorization'] = f"Basic {BASE64_ENCODED_HEADER_STRING}"

data['grant_type'] = "client_credentials"
data['json'] = True
data['scope'] = 'user-read-recently-played'

r = requests.post(url=token_request_url, headers=headers, data=data)

# prints the response from the server regarding the access token data (formatted to be easier to read)
print(json.dumps(r.json(), indent=2))    
  
# store the token value in a variable for HTTP GET request  
token = r.json()['access_token']

不清楚的是,我首先需要使用凭据发布我的请求以获取令牌(使用特定的 URL 来执行),将 r.json()['access_token'] 值存储在变量中,然后将其用作一部分以下 GET 请求访问我的特定数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM