DRF第三方应用登录问题:Python脚本调用api/user/profile鉴权失败
问题排查与解决方案
你的脚本核心问题是认证流程不匹配:你平时用JWT保护API,但脚本里走的是DRF可浏览API的Session登录流程,两者凭证不兼容,所以即便Session登录成功,访问JWT保护的端点仍会提示“未提供认证凭证”。下面分点拆解问题并给出修复方案:
一、核心问题分析
- 认证方式错配:
api-auth/login/是DRF为可浏览API设计的Session认证入口,而你的API用JWT保护,Session的cookie凭证不被JWT认证后端识别。 - CSRF提取不可靠:用正则匹配
"(HTML转义引号)容易失败,DRF实际会把CSRF token存在csrftokencookie里,直接从cookie提取更稳定。 - 登录字段可能错误:DRF默认登录表单用
username字段,你脚本里传的是email,如果后台没配置用邮箱作为用户名,这会直接导致登录失败。
二、修复脚本(JWT认证版本)
如果你的API用的是djangorestframework-simplejwt这类JWT插件,直接调用JWT的token获取接口即可,无需走Session登录页面:
import requests def get_jwt_token_and_profile(email, password, api_base_url): # 1. 调用JWT token接口(默认simplejwt的接口是api/token/) token_url = f"{api_base_url}api/token/" token_payload = { "username": email, # 后台用邮箱当用户名就填email,否则填实际用户名 "password": password } token_response = requests.post(token_url, data=token_payload) if token_response.status_code != 200: print(f"获取token失败: {token_response.content.decode()}") return token_data = token_response.json() access_token = token_data.get("access") if not access_token: print("响应中未返回access token") return # 2. 用JWT token访问用户profile接口 profile_url = f"{api_base_url}api/users/profile/" headers = { "Authorization": f"Bearer {access_token}" } profile_response = requests.get(profile_url, headers=headers) if profile_response.status_code == 200: print("用户profile数据:") print(profile_response.json()) else: print(f"访问profile失败: {profile_response.content.decode()}") # 调用示例 email = "t.user@test.com" password = "testpass" api_base_url = "https://admin.myapp.com/" get_jwt_token_and_profile(email, password, api_base_url)
三、如果必须用Session认证(仅当API允许时)
如果你的API同时开启了Session认证(settings.py的DEFAULT_AUTHENTICATION_CLASSES里加了SessionAuthentication),可以修正原脚本的问题:
- CSRF提取改为从cookie获取,替代不稳定的正则匹配;
- 登录字段改为
username,如果后台用邮箱当用户名,确保User模型的USERNAME_FIELD设为email; - 登录成功判断改为检查
sessionidcookie,因为DRF登录成功会重定向,返回码是302而非200。
修正后的Session版本脚本:
import requests def get_csrf_token(session): return session.cookies.get('csrftoken') def login_and_get_user_data(email, password, api_base_url, referer_url): session = requests.Session() # 1. 访问登录页面获取CSRF cookie login_url = f"{api_base_url}api-auth/login/?next=/api/users/profile/" session.get(login_url, headers={'Referer': referer_url}) csrf_token = get_csrf_token(session) if not csrf_token: print("CSRF token未找到") return # 2. 提交登录表单 login_payload = { "username": email, # 注意字段是username,不是email "password": password, "csrfmiddlewaretoken": csrf_token } response = session.post(login_url, data=login_payload, headers={'Referer': referer_url, 'Content-Type': 'application/x-www-form-urlencoded'}) # 通过sessionid cookie判断登录是否成功 if 'sessionid' in session.cookies: print("登录成功") user_profile_url = f"{api_base_url}api/users/profile/" user_profile_response = session.get(user_profile_url, headers={'Referer': referer_url}) print(f"用户Profile数据: {user_profile_response.content.decode()}") else: print("登录失败") print(f"响应内容: {response.content.decode()}") # 调用示例 email = "t.user@test.com" password = "testpass" api_base_url = "https://admin.myapp.com/" referer_url = api_base_url login_and_get_user_data(email, password, api_base_url, referer_url)
四、关键注意事项
- 确认
api/users/profile/的认证类:JWT保护的话必须带Authorization: Bearer <token>头;Session保护的话必须保留sessionidcookie,POST/PUT等方法还要带CSRF头。 - 检查DRF配置
settings.py中的DEFAULT_AUTHENTICATION_CLASSES,确认启用了对应的认证方式。 - 用JWT的话,记得处理
refresh_token的刷新逻辑,避免token过期无法访问。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

