Vue.js与Django认证会话保持失败求助:用request jar仍遇403错误
会话持久化问题排查与解决方案
我来帮你搞定这个会话无法持久的问题,你遇到的403错误大概率和CSRF令牌处理、会话Cookie的保存/发送逻辑有关,咱们一步步来解决:
1. 先解决CSRF令牌的核心问题
虽然你的Login视图加了csrf_exempt,但后续被user_login_required保护的视图默认会校验CSRF令牌(除非你也给它们加了csrf_exempt,但这非常不安全)。Django的会话认证依赖CSRF Cookie和请求头里的CSRF令牌配对,而你当前的代码没处理这个流程,这是403的主要原因。
修复步骤:
- 登录前先向Django获取CSRF令牌Cookie
- 登录时同时发送账号密码和CSRF令牌请求头
修改你的Vue代码:
var request = require('request'); // 新增:获取CSRF令牌的方法 get_csrf_token() { return new Promise((resolve, reject) => { // 先发送GET请求获取Django的CSRF Cookie request({ url: '/api/get-csrf-token/', // 需要在Django中新增这个接口 jar: this.get_jar(), method: 'GET' }, (err, res) => { if (err) reject(err); // 从jar中提取csrftoken值 const cookieStr = this.get_jar().getCookieString(res.request.uri); const csrfToken = cookieStr.split(';').find(item => item.trim().startsWith('csrftoken='))?.split('=')[1]; resolve(csrfToken); }); }); } // 修改send_ajax,支持传入CSRF令牌 send_ajax(url, data, method, callback, csrfToken = null) { const options = { url: url, method: method, form: data, jar: this.get_jar(), headers: {} }; // 有CSRF令牌时,添加到请求头 if (csrfToken) { options.headers['X-CSRFToken'] = csrfToken; } request(options, function(err, res, body){ callback(err, res, body) }); } // 调整登录流程:先拿CSRF令牌再登录 async login(email, password) { try { const csrfToken = await this.get_csrf_token(); this.send_ajax('/api/login/', {email, password}, 'POST', (err, res, body) => { if (res.statusCode === 200) { console.log('登录成功'); // 后续请求复用同一个jar和CSRF令牌 this.send_ajax('/api/protected/', {}, 'GET', (err, res, body) => { // 这里应该能正常访问受保护接口了 }, csrfToken); } }, csrfToken); } catch (err) { console.error('获取CSRF令牌失败:', err); } }
在Django中新增获取CSRF令牌的接口:
from django.views.decorators.csrf import ensure_csrf_cookie from django.http import JsonResponse @ensure_csrf_cookie def get_csrf_token(request): return JsonResponse({'message': 'CSRF Cookie已设置'})
别忘了在urls.py中给这个接口配置路由。
2. 检查Django的会话Cookie配置
打开settings.py,确保会话相关配置正确,尤其是跨域、SameSite属性:
# settings.py SESSION_COOKIE_SAMESITE = 'Lax' # 同域场景用Lax即可,跨域场景需设为None(同时要开启SESSION_COOKIE_SECURE=True) SESSION_COOKIE_HTTPONLY = False # 测试阶段先设为False,确保jar能捕获Cookie(线上环境可改回True) SESSION_COOKIE_DOMAIN = None # 同域留空,跨域需设置为前端域名 SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 确保用默认的数据库会话引擎
3. 确保Jar全局复用
检查你的Vue组件中this.jar是否在多实例中被重复创建。最好把Jar放在全局状态管理(比如Vuex)或者单例工具类中,确保所有请求共用同一个Jar:
// 单独创建api.js工具文件 const request = require('request'); let globalJar = null; export function getGlobalJar() { if (!globalJar) { globalJar = request.jar(); } return globalJar; } // 所有请求都调用这个方法获取Jar
4. 验证会话Cookie是否被正确保存
在登录回调中打印Jar内的Cookie,确认是否包含Django的sessionid和csrftoken:
this.send_ajax('/api/login/', {email, password}, 'POST', (err, res, body) => { console.log('Jar内的Cookie:', this.get_jar().getCookieString(res.request.uri)); // 正常情况下应该看到类似:sessionid=xxxx; csrftoken=xxxx }, csrfToken);
如果看不到sessionid,说明Django的login(request, user)没有正确设置会话Cookie,需要检查Django的会话引擎配置是否正常。
内容的提问来源于stack exchange,提问作者hamid
相关产品推荐
相关产品推荐

