You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DRF第三方应用登录问题:Python脚本调用api/user/profile鉴权失败

问题排查与解决方案

你的脚本核心问题是认证流程不匹配:你平时用JWT保护API,但脚本里走的是DRF可浏览API的Session登录流程,两者凭证不兼容,所以即便Session登录成功,访问JWT保护的端点仍会提示“未提供认证凭证”。下面分点拆解问题并给出修复方案:

一、核心问题分析

  1. 认证方式错配:api-auth/login/是DRF为可浏览API设计的Session认证入口,而你的API用JWT保护,Session的cookie凭证不被JWT认证后端识别。
  2. CSRF提取不可靠:用正则匹配"(HTML转义引号)容易失败,DRF实际会把CSRF token存在csrftoken cookie里,直接从cookie提取更稳定。
  3. 登录字段可能错误: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),可以修正原脚本的问题:

  1. CSRF提取改为从cookie获取,替代不稳定的正则匹配;
  2. 登录字段改为username,如果后台用邮箱当用户名,确保User模型的USERNAME_FIELD设为email;
  3. 登录成功判断改为检查sessionid cookie,因为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保护的话必须保留sessionid cookie,POST/PUT等方法还要带CSRF头。
  • 检查DRF配置settings.py中的DEFAULT_AUTHENTICATION_CLASSES,确认启用了对应的认证方式。
  • 用JWT的话,记得处理refresh_token的刷新逻辑,避免token过期无法访问。

内容的提问来源于stack exchange,提问作者Adrian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 00:40:03