[英]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.get
、 requests.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.