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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:12:17