Python使用requests发起GET授权请求如何获取回调授权码
问题根因
当前实现逻辑存在本质错误:
requests库发起的HTTP请求和webbrowser唤起的系统浏览器是完全独立的两个HTTP客户端,你预先用requests.get拿到的只是授权端点的初始构造URL,授权完成后的302跳转动作完全发生在浏览器侧,你的Python程序既没有参与这个跳转流程,也没有监听对应重定向地址的端口,自然拿不到返回内容。- 授权码是携带在跳转后URL的query参数中,并非藏在初始授权接口的响应体里,你最开始调用
requests.get的逻辑本身就是多余的。
实现方案
OAuth2授权码模式的本地回调核心逻辑非常简单:在本地启动一个临时HTTP服务,监听你在开放平台预先配置的重定向URI对应的端口和路径,等用户完成授权、浏览器自动跳转到这个本地地址时,直接从请求的query参数里解析出code字段即可,不需要额外部署公网回调服务。
具体步骤
- 先去应用的开放平台配置页,把重定向URL设置为本地地址,比如
http://localhost:8888/callback,端口选一个没被占用的即可,路径只要和后续监听的路径保持一致就行。 - 不需要提前用
requests请求授权端点,直接拼接好带业务参数的授权URL,交给浏览器打开即可。 - 在唤起浏览器之前,先启动本地临时HTTP服务阻塞等待回调,解析到授权码之后立刻关闭临时服务,继续执行后续换token的业务逻辑。
参考实现代码
直接用Python标准库就能实现,不需要安装额外第三方依赖:
import webbrowser import requests from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import urlparse, parse_qs # 替换成你自己的应用配置 CLIENT_ID = "你的应用客户端ID" CLIENT_SECRET = "你的应用客户端密钥" AUTH_ENDPOINT = "平台授权接口地址" TOKEN_ENDPOINT = "平台token换取接口地址" REDIRECT_URI = "http://localhost:8888/callback" SCOPE = "你需要申请的权限范围" LISTEN_PORT = 8888 auth_code = None class CallbackHandler(BaseHTTPRequestHandler): def do_GET(self): global auth_code # 解析回调请求的参数 query_params = parse_qs(urlparse(self.path).query) if 'code' in query_params: auth_code = query_params['code'][0] # 给浏览器返回授权成功提示 self.send_response(200) self.send_header('Content-Type', 'text/html; charset=utf-8') self.end_headers() self.wfile.write(b"<h3>授权成功,可关闭当前页面返回程序</h3>") else: self.send_response(400) self.end_headers() self.wfile.write(b"授权失败,未获取到有效授权码") # 处理完回调立刻关闭临时服务 self.server.shutdown() # 屏蔽HTTP服务默认的控制台日志输出,不需要可以删掉这段 def log_message(self, format, *args): return if __name__ == "__main__": # 构造授权访问URL auth_query = { "response_type": "code", "client_id": CLIENT_ID, "redirect_uri": REDIRECT_URI, "scope": SCOPE # 生产环境请增加state参数做CSRF校验,这里做简化省略 } auth_url = requests.Request("GET", AUTH_ENDPOINT, params=auth_query).prepare().url # 启动本地临时监听服务 local_server = HTTPServer(("0.0.0.0", LISTEN_PORT), CallbackHandler) # 打开系统浏览器跳转到授权页 webbrowser.open(auth_url, new=0, autoraise=True) # 阻塞等待回调请求 local_server.serve_forever() # 走到这里已经拿到授权码,可继续执行换取access_token逻辑 print(f"获取到的授权码:{auth_code}") token_query = { "grant_type": "authorization_code", "code": auth_code, "redirect_uri": REDIRECT_URI, "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET } token_resp = requests.post(TOKEN_ENDPOINT, data=token_query).json() print("换取到的凭证信息:", token_resp)
注意事项
- 如果对接的平台不允许使用localhost作为重定向地址,强制要求HTTPS公网回调地址,要么单独部署公网服务接收回调请求,要么改用平台支持的其他授权模式(比如设备码模式),不要硬改本地逻辑。
- 正式环境必须加
state参数校验:发起授权时生成随机字符串存在本地,回调时比对请求带回的state值和本地存储的是否一致,避免CSRF攻击。 - 启动临时服务前要确认监听端口没有被其他程序占用,否则会启动失败。
内容的提问来源于stack exchange,提问作者gemaltemusik
相关产品推荐
相关产品推荐

