中间件的应用:统一处理登录验证与请求拦截
在 Django 项目中,当多个功能需要统一的登录验证、权限检查等逻辑时,重复在视图函数中编写校验代码会导致代码冗余。中间件作为 Django 请求 / 响应的 “拦截过滤器”,能将这类通用逻辑抽离出来,实现代码复用和业务解耦。本文将详解 Django 中间件的核心概念、内置中间件作用,并通过实战演示如何自定义中间件实现登录验证。
一、Django 中间件核心概述
中间件是嵌入在 Web 应用请求 - 响应流程中的组件,可拦截、过滤、修改请求和响应,专注于完成通用横切功能(如登录验证、日志记录、CSRF 防护、会话管理等)。Django 框架本身就内置了多个核心中间件,通过组合不同中间件实现复杂的通用能力。
1. 内置中间件配置与作用
Django 的settings.py中默认配置了以下核心中间件,各司其职:
MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',]
核心内置中间件详解
| | |
CommonMiddleware | | APPEND_SLASH(URL 补/)、DISALLOWED_USER_AGENTS(禁用用户代理) |
SecurityMiddleware | | SECURE_SSL_REDIRECT(强制 HTTPS)、SECURE_BROWSER_XSS_FILTER(XSS 过滤) |
SessionMiddleware | 会话管理(为 request 绑定session对象) | SESSION_COOKIE_AGE(会话有效期)、SESSION_ENGINE(会话存储引擎) |
CsrfViewMiddleware | | CSRF_COOKIE_SECURE |
XFrameOptionsMiddleware | | X_FRAME_OPTIONS |
2. 中间件执行顺序
- • 请求阶段:中间件按
MIDDLEWARE列表从上到下执行,完成拦截 / 处理后,请求才会进入 URL 解析和视图函数; - • 响应阶段:中间件按
MIDDLEWARE列表从下到上执行,可对响应做最终修改后返回给用户; - • 拦截规则:若某中间件在请求阶段直接返回响应(如重定向、JSON 提示),后续中间件和视图函数将不再执行。
二、自定义中间件:统一登录验证
1. 需求场景
需对投票、导出 Excel、查看统计图表等功能做登录限制,避免在每个视图函数中重复编写session校验代码。
2. 中间件实现方式
Django 支持两种自定义中间件的方式:基于函数(推荐,接近装饰器写法)、基于类(旧版写法,兼容低版本 Django)。方式 1:基于函数的中间件(推荐)在项目根目录创建middlewares.py,编写登录验证中间件:
"""middlewares.py"""from django.http import JsonResponsefrom django.shortcuts import redirect# 需要登录才能访问的资源路径LOGIN_REQUIRED_URLS = {'/praise/', '/criticize/', '/excel/', '/teachers_data/'}defcheck_login_middleware(get_resp):defwrapper(request, *args, **kwargs):# 请求的资源路径在上面的集合中if request.path in LOGIN_REQUIRED_URLS:# 会话中包含userid则视为已经登录if'userid'notin request.session:# 判断是不是Ajax请求if request.is_ajax():# Ajax请求返回JSON数据提示用户登录return JsonResponse({'code': 10003, 'hint': '请先登录'})else: backurl = request.get_full_path()# 非Ajax请求直接重定向到登录页return redirect(f'/login/?backurl={backurl}')return get_resp(request, *args, **kwargs)return wrapper
方式 2:基于类的中间件(旧版兼容写法)适用于低版本 Django,需继承MiddlewareMixin,重写钩子函数:
from django.utils.deprecation import MiddlewareMixinclassMyMiddleware(MiddlewareMixin):defprocess_request(self, request):passdefprocess_view(self, request, view_func, view_args, view_kwargs):passdefprocess_template_response(self, request, response):passdefprocess_response(self, request, response):passdefprocess_exception(self, request, exception):pass
上面类中的五个方法都是中间件的钩子函数,分别在收到用户请求、进入视图函数之前、渲染模板、返回响应和出现异常的时候被回调。当然,写不写这些方法是根据中间件的需求来确定的,并不是所有的场景都需要重写五个方法,下面的图相信能够帮助大家理解这种写法。
3. 激活自定义中间件
修改settings.py的MIDDLEWARE列表,添加自定义中间件(注意顺序):
MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware','debug_toolbar.middleware.DebugToolbarMiddleware','vote.middlewares.check_login_middleware',]
4.关键注意事项
- • 登录验证中间件需放在SessionMiddleware之后(依赖request.session);
- • 若中间件依赖其他内置中间件(如AuthenticationMiddleware),需保证被依赖的中间件在前;
- 2. URL 匹配优化:若需支持模糊匹配(如
/api/*),可改用正则表达式:
import reLOGIN_REQUIRED_PATTERNS = [ re.compile(r'^/praise/'), re.compile(r'^/excel/')]# 匹配逻辑ifany(pattern.match(request.path) for pattern in LOGIN_REQUIRED_PATTERNS):# 登录校验逻辑
- 3. 兼容 Ajax 请求:前端 Ajax 请求被拦截时,返回 JSON 而非重定向,避免前端解析异常;
- 4. 登录后回跳:重定向到登录页时携带
backurl参数,登录成功后可通过该参数返回原页面:
# 登录视图函数示例deflogin(request):if request.method == 'POST':# 验证用户信息...# 登录成功后回跳 backurl = request.GET.get('backurl', '/')return redirect(backurl)return render(request, 'login.html')
三、中间件扩展场景
除登录验证外,中间件还可实现以下通用功能:
- 1. 接口限流:记录 IP 请求频率,限制高频访问;
- 2. 日志记录:统一记录所有请求的 URL、耗时、响应状态;
- 3. 跨域处理:添加 CORS 响应头,解决前端跨域问题;
- 5. 数据加密 / 解密:对请求 / 响应数据做加解密处理。示例:接口限流中间件
"""接口限流中间件:限制单IP每分钟最多请求60次"""import timefrom django.http import JsonResponsefrom collections import defaultdict# 存储IP请求记录:{ip: [请求时间1, 请求时间2, ...]}IP_REQUEST_RECORDS = defaultdict(list)defrate_limit_middleware(get_response):defmiddleware(request, *args, **kwargs): client_ip = request.META.get('REMOTE_ADDR') current_time = time.time()# 清理1分钟前的请求记录 IP_REQUEST_RECORDS[client_ip] = [t for t in IP_REQUEST_RECORDS[client_ip] if current_time - t < 60]# 检查请求频率iflen(IP_REQUEST_RECORDS[client_ip]) >= 60:return JsonResponse({'code': 10004, 'msg': '请求过于频繁,请1分钟后重试'})# 记录本次请求时间 IP_REQUEST_RECORDS[client_ip].append(current_time)return get_response(request, *args, **kwargs)return middleware
总结
- 1. 中间件是 Django 处理通用横切逻辑的核心组件,请求阶段从上到下执行,响应阶段从下到上执行,可拦截请求 / 修改响应;
- 2. 自定义中间件推荐使用函数式写法,需注意执行顺序(依赖 session 的中间件需放在
SessionMiddleware之后); - 3. 登录验证中间件可统一拦截未登录请求,区分 Ajax / 普通请求返回不同响应,避免视图函数代码冗余;
- 4. 中间件还可扩展实现接口限流、日志记录、跨域处理等通用功能,是 Django 项目解耦和复用的关键手段。
AI工具,提高学习,工作效率,神器