如何通过Fetch、Ajax及React向DRF后端发送认证令牌?
基于DRF的令牌认证实现方案
一、后端DRF配置
要替换Basic认证为令牌认证,首先在DRF中启用TokenAuthentication,步骤如下:
- 在项目
settings.py的INSTALLED_APPS中添加rest_framework.authtoken - 配置DRF的认证与权限类:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ] }
- 执行迁移命令生成存储令牌的数据表:
python manage.py migrate
- 在
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
相关产品推荐
相关产品推荐

