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

如何通过Fetch、Ajax及React向DRF后端发送认证令牌?

基于DRF的令牌认证实现方案

一、后端DRF配置

要替换Basic认证为令牌认证,首先在DRF中启用TokenAuthentication,步骤如下:

  1. 在项目settings.py的INSTALLED_APPS中添加rest_framework.authtoken
  2. 配置DRF的认证与权限类:
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}
  1. 执行迁移命令生成存储令牌的数据表:
python manage.py migrate
  1. 在urls.py中添加获取令牌的接口路由:
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
    # 其他业务路由
    path('api/token/', obtain_auth_token, name='api_token_auth'),
]

二、原生Ajax实现令牌认证流程

1. 获取认证令牌

先通过用户名密码调用令牌接口获取凭证:

function getAuthToken(username, password, callback) {
  $.ajax({
    url: '/api/token/',
    type: 'POST',
    data: {
      username: username,
      password: password
    },
    success: function(response) {
      // 将令牌存入本地存储,方便后续请求使用
      localStorage.setItem('auth_token', response.token);
      if (callback) callback(response.token);
    },
    error: function(xhr) {
      console.error('获取令牌失败:', xhr.responseText);
    }
  });
}

2. 修改通用请求方法

替换原Basic认证逻辑,改用令牌发起请求:

function ajaxCall(type, url, data, callback) {
  const authToken = localStorage.getItem('auth_token');
  $.ajax({
    url: url,
    type: type,
    data: data,
    headers: {
      "Authorization": "Token " + authToken
    },
    success: function (response, status, xhr) {
      console.log(response);
      console.log(xhr);
      if (xhr.status !== 204 && callback) {
        callback(response);
      }
    },
    error: function (xhr, status, error) {
      console.error("请求出错:", xhr.responseText, status, error);
      // 令牌失效时触发重新登录逻辑
      if (xhr.status === 401) {
        console.log('令牌无效,请重新登录');
        localStorage.removeItem('auth_token');
        // 可在此处跳转登录页
      }
    },
  });
}

3. 使用示例

// 先登录获取令牌
getAuthToken('你的用户名', '你的密码', function(token) {
  // 令牌获取成功后调用业务接口
  ajaxCall('GET', '/api/lotteries/', null, function(data) {
    console.log('彩票数据:', data);
  });
});

三、React.js中的实现方案

1. 封装请求工具类

创建api.js统一处理请求逻辑:

const BASE_URL = 'http://你的后端域名/api';

// 获取认证令牌
export const getAuthToken = async (username, password) => {
  try {
    const response = await fetch(`${BASE_URL}/token/`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: new URLSearchParams({
        username,
        password
      })
    });
    if (!response.ok) throw new Error('登录失败');
    const data = await response.json();
    localStorage.setItem('auth_token', data.token);
    return data.token;
  } catch (error) {
    console.error('获取令牌失败:', error);
    throw error;
  }
};

// 通用业务请求方法
export const apiCall = async (method, endpoint, data = null) => {
  const authToken = localStorage.getItem('auth_token');
  const headers = {
    'Authorization': `Token ${authToken}`,
    'Content-Type': 'application/json'
  };

  const options = {
    method,
    headers,
  };

  if (data) {
    options.body = JSON.stringify(data);
  }

  try {
    const response = await fetch(`${BASE_URL}${endpoint}`, options);
    if (!response.ok) {
      if (response.status === 401) {
        localStorage.removeItem('auth_token');
        throw new Error('令牌失效,请重新登录');
      }
      throw new Error('请求失败');
    }
    // 处理无返回内容的情况
    if (response.status === 204) return null;
    return await response.json();
  } catch (error) {
    console.error('请求出错:', error);
    throw error;
  }
};

2. 组件中使用示例

登录组件

import { useState } from 'react';
import { getAuthToken } from './api';

const Login = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleLogin = async () => {
    try {
      await getAuthToken(username, password);
      alert('登录成功');
      window.location.href = '/dashboard';
    } catch (error) {
      alert('登录失败,请检查用户名密码');
    }
  };

  return (
    <div className="login-container">
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        placeholder="用户名"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="密码"
      />
      <button onClick={handleLogin}>登录</button>
    </div>
  );
};

export default Login;

彩票列表组件

import { useEffect, useState } from 'react';
import { apiCall } from './api';

const LotteryList = () => {
  const [lotteries, setLotteries] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const data = await apiCall('GET', '/lotteries/');
        setLotteries(data);
      } catch (error) {
        alert(error.message);
        window.location.href = '/login';
      }
    };
    fetchData();
  }, []);

  return (
    <div>
      <h2>彩票列表</h2>
      <ul>
        {lotteries.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default LotteryList;

注意事项

  • 令牌存储在localStorage存在XSS风险,生产环境可配合后端改用HttpOnly Cookie存储令牌
  • 后端需处理令牌过期、无效场景,返回401状态码,前端收到后清除本地令牌并引导用户重新登录
  • 若需更灵活的令牌机制,可使用JWT认证,DRF可通过djangorestframework-simplejwt包实现

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:52:08