如何让Django2.1.4站点所有URL仅对注册用户开放?自定义Middleware失效
解决Django 2.1.4自定义权限中间件失效问题
我来帮你排查这个中间件的问题——你的代码有两个关键错误导致它没生效,咱们一步步来修正:
问题根源
- 新中间件模式不自动执行
process_request方法:你用了Django 1.10+引入的新中间件结构(包含__init__和__call__方法),但仍然保留了旧模式的process_request方法,这个方法在新结构中不会被自动调用。 is_authenticated调用方式错误:Django 2.1中request.user.is_authenticated是一个属性,不是方法,你加了括号()会导致逻辑判断出错(甚至语法错误)。- 缺少登录页排除逻辑:如果不排除登录页面,未登录用户会被无限重定向到登录页,陷入循环。
修正后的中间件代码(推荐新模式)
from django.http import HttpResponseRedirect from django.urls import reverse class MyAuthorization: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 请求到达视图前的权限验证逻辑(必须放在get_response调用前) # 排除登录页面,避免无限重定向 login_url = reverse('login') # 替换成你实际的登录URL名称 if not request.user.is_authenticated and request.path != login_url: return HttpResponseRedirect(login_url) # 继续执行后续中间件和视图 response = self.get_response(request) # 这里可以添加响应返回后的处理逻辑(如果需要) return response
另一种兼容旧模式的写法(不推荐长期使用)
如果你更习惯旧的process_request写法,可以继承MiddlewareMixin来兼容:
from django.http import HttpResponseRedirect from django.urls import reverse from django.utils.deprecation import MiddlewareMixin class MyAuthorization(MiddlewareMixin): def process_request(self, request): login_url = reverse('login') if not request.user.is_authenticated and request.path != login_url: return HttpResponseRedirect(login_url) return None
关键注意事项
- 中间件顺序:你的
settings.py中MyAuthorization放在AuthenticationMiddleware之后是正确的,因为AuthenticationMiddleware会把用户对象绑定到request.user上,你的中间件才能正确获取用户认证状态。 - 避免硬编码URL:用
reverse('login')代替硬编码的'/',这样如果后续修改登录URL配置,不需要修改中间件代码。 - 测试边缘情况:记得测试登录用户访问、未登录用户访问非登录页、未登录用户访问登录页这几种场景,确保逻辑正常。
内容的提问来源于stack exchange,提问作者tesoro




