Django会话过期后实现任意操作跳转至登录页的方案咨询
解决Django会话过期后页面任意操作触发登录跳转的问题
针对你的Django 1.9 + Python 3.5开发场景,要实现页面任意操作(包括AJAX请求、表单提交、按钮点击等)都能触发登录页跳转,需要结合后端中间件的会话检查逻辑和前端的全局请求/响应拦截,下面是具体实现方案:
一、完善自定义SessionMiddleware,强化会话过期检测
你当前的中间件只在响应阶段重置会话过期时间,缺少主动检查会话是否过期的逻辑。修改中间件代码,让它能对所有请求(包括AJAX)做过期校验,并返回明确的状态码供前端识别:
# -*- coding: utf-8 -*- try: from django.utils.deprecation import MiddlewareMixin except ImportError: MiddlewareMixin = object from django.http import HttpResponseRedirect, JsonResponse from django.core.urlresolvers import reverse # Django 1.9用这个,2.x+请用reverse_lazy from datetime import datetime, timedelta class SessionMiddleware(MiddlewareMixin): def process_request(self, request): # 排除登录页面,避免循环跳转 login_url = reverse('login') # 替换成你项目中登录视图的URL name if request.path == login_url: return # 处理已认证用户的会话检查 if hasattr(request, 'user') and request.user.is_authenticated(): # 获取会话最后活跃时间,判断是否超过30分钟(1800秒) last_activity = request.session.get('last_activity') if last_activity: current_time = datetime.now() time_diff = current_time - datetime.fromtimestamp(last_activity) if time_diff > timedelta(seconds=1800): # 会话过期,清除会话 request.session.flush() # 区分AJAX和普通请求,返回对应响应 if request.is_ajax(): return JsonResponse({'msg': '会话已过期,请重新登录'}, status=401) else: return HttpResponseRedirect(login_url) # 更新会话最后活跃时间 request.session['last_activity'] = datetime.now().timestamp() else: # 未认证用户:普通请求跳登录,AJAX返回401 if not request.is_ajax(): return HttpResponseRedirect(login_url) else: return JsonResponse({'msg': '请先登录'}, status=401) def process_response(self, request, response): # 保留原有逻辑:用户活跃时重置会话过期时间 if hasattr(request, 'user') and request.user.is_authenticated(): request.session.set_expiry(1800) return response
重要提示:记得把
reverse('login')里的login替换成你项目中登录URL的实际name(在urls.py中定义的)。
二、前端全局拦截请求/响应,处理过期跳转
页面上的大部分操作都会触发AJAX请求(比如异步表单提交、按钮点击调用接口),需要统一监听这些请求的响应,一旦收到后端返回的401状态码,就自动跳转到登录页。下面分两种情况给出代码:
1. 用jQuery的项目
在全局JS文件中添加以下代码:
// 监听所有AJAX请求的完成事件 $(document).ajaxComplete(function(event, xhr, settings) { if (xhr.status === 401) { alert('会话已过期,请重新登录'); window.location.href = '/login/'; // 替换成你的实际登录URL } }); // 处理非AJAX表单提交(保险措施,后端其实已经会跳转) $('form').submit(function(e) { $.get('/check_session/', function(data) { if (!data.is_valid) { window.location.href = '/login/'; e.preventDefault(); } }).fail(function() { window.location.href = '/login/'; e.preventDefault(); }); });
2. 原生JS项目
如果不用jQuery,通过重写XMLHttpRequest来全局监听:
// 重写XMLHttpRequest的send方法,添加响应监听 const originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { this.addEventListener('load', function() { if (this.status === 401) { alert('会话已过期,请重新登录'); window.location.href = '/login/'; } }); originalSend.apply(this, arguments); }; // 监听所有表单提交事件 document.addEventListener('submit', function(e) { fetch('/check_session/') .then(res => res.json()) .then(data => { if (!data.is_valid) { window.location.href = '/login/'; e.preventDefault(); } }) .catch(() => { window.location.href = '/login/'; e.preventDefault(); }); });
可选:主动定时检查会话状态
如果想在用户长时间未操作时主动提示跳转,可以添加一个定时任务:
// 每5分钟检查一次会话状态 setInterval(function() { fetch('/check_session/') .then(res => res.json()) .then(data => { if (!data.is_valid) { alert('会话即将过期,请重新登录'); window.location.href = '/login/'; } }); }, 300000); // 300000毫秒 = 5分钟
对应的,需要在后端添加一个check_session视图:
from django.http import JsonResponse from django.contrib.auth.decorators import login_required @login_required def check_session(request): return JsonResponse({'is_valid': True})
并在urls.py中配置路由:
urlpatterns = [ # ... 其他路由 url(r'^check_session/$', views.check_session, name='check_session'), ]
三、关键配置注意事项
- 确保
MIDDLEWARE_CLASSES中,自定义的zeus.middleware.SessionMiddleware放在django.contrib.auth.middleware.AuthenticationMiddleware之后,这样才能正确获取request.user对象。 - Django 1.9中的
request.is_ajax()是有效可用的,无需担心兼容性问题。 - 测试前请清除浏览器缓存和旧会话,避免干扰测试结果。
内容的提问来源于stack exchange,提问作者yinfu
相关产品推荐
相关产品推荐

