使用Django REST Framework与django-rest-knox实现HttpOnly Cookie存储认证令牌后,如何通过React和Axios访问受保护路由
嘿,你其实已经走对了关键一步——用HttpOnly Cookie存token是非常安全的做法!这里的核心点是:HttpOnly Cookie会被浏览器自动附加到同域(或符合CORS配置的跨域)请求中,根本不需要你手动通过JavaScript获取token再塞到Authorization头里。下面一步步帮你搞定整个流程:
1. 后端先搞定CORS和Token认证适配
首先要确保后端允许前端携带凭证(Cookie),并且能从Cookie里读取knox的token进行验证:
配置CORS(用django-cors-headers)
如果还没装,先安装django-cors-headers,然后在settings.py里做如下配置:
INSTALLED_APPS = [ # ... 其他app 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # 要放在CommonMiddleware前面 'django.middleware.common.CommonMiddleware', # ... 其他中间件 ] # 允许携带Cookie CORS_ALLOW_CREDENTIALS = True # 允许你的前端域名(开发环境是localhost:3000,生产环境换成实际域名) CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", ]
自定义Token认证类(从Cookie取token)
knox默认是从Authorization头取token,现在我们要改成从Cookie读取。在你的app下新建authentication.py:
from rest_framework.exceptions import AuthenticationFailed from knox.auth import TokenAuthentication class CookieTokenAuthentication(TokenAuthentication): def authenticate(self, request): # 从Cookie中获取我们存的auth_token token = request.COOKIES.get('auth_token') if not token: return None # 复用knox的token验证逻辑 try: return self.authenticate_credentials(token) except AuthenticationFailed: return None
然后在settings.py里把这个认证类设为默认,或者在单个视图里指定:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'your_app_name.authentication.CookieTokenAuthentication', # 可以保留原来的TokenAuthentication,兼容两种认证方式 'knox.auth.TokenAuthentication', ], }
2. 前端Axios配置(自动携带Cookie)
只需要给Axios设置withCredentials: true,浏览器就会自动把HttpOnly Cookie附加到请求里了。建议创建一个全局Axios实例:
在src/utils/axios.js里:
import axios from 'axios'; const axiosInstance = axios.create({ baseURL: 'http://localhost:8000/api/', // 替换成你的API base地址 withCredentials: true, // 关键!开启后浏览器自动携带Cookie }); // 针对POST/PUT/DELETE等修改请求,需要带上CSRF Token(Django默认开启CSRF保护) axiosInstance.interceptors.request.use((config) => { // 从可访问的csrftoken Cookie中取值 const csrfToken = document.cookie.split('; ') .find(row => row.startsWith('csrftoken='))?.split('=')[1]; if (csrfToken) { config.headers['X-CSRFToken'] = csrfToken; } return config; }); export default axiosInstance;
之后在组件里直接用这个实例请求受保护路由就行:
import axiosInstance from '../utils/axios'; const fetchProtectedData = async () => { try { const response = await axiosInstance.get('/protected-endpoint/'); console.log('受保护数据:', response.data); } catch (error) { console.error('请求失败:', error); // 处理未认证情况,比如跳回登录页 if (error.response.status === 401) { window.location.href = '/login'; } } };
几个额外注意点
- SameSite设置:你代码里已经设了
samesite='strict',这是最安全的配置,适合前后端同域的场景;如果是跨域场景,可能需要调整为'lax',但优先保持strict。 - 登出逻辑:登出时要后端清除Cookie,比如在knox的登出视图里添加
response.delete_cookie('auth_token')。 - 生产环境配置:要确保前后端都使用HTTPS,Cookie加上
secure=True,进一步提升安全性。
内容的提问来源于stack exchange,提问作者Fady's Cube
相关产品推荐
相关产品推荐

