Django如何为指定路由配置自定义角色认证中间件
Django指定路由应用权限校验的最优实现方案
你想要的类似Laravel路由绑定中间件的效果,Django有几种等价且灵活的实现方式:
方案1:路由层批量绑定装饰器(最贴合Laravel使用习惯)
这种方式和Laravel中路由组指定中间件的逻辑完全一致,不需要全局注册中间件,也不用逐个给视图加装饰器:
首先把你的中间件转为装饰器,直接在urls.py中批量应用:
# urls.py from django.urls import path, include from django.utils.decorators import decorator_from_middleware from .middlewares import HRMiddleware from . import views # 把中间件转为装饰器 hr_permission_required = decorator_from_middleware(HRMiddleware) urlpatterns = [ # 公开路由,不需要校验 path('public/', views.public_page), # 单个路由绑定校验 path('edit/uploaded-files', hr_permission_required(views.uploaded_files_edit)), # 批量给一组路由绑定校验,和Laravel路由组效果完全一致 path('hr-manage/', hr_permission_required(include('hr_module.urls'))), ]
如果是类视图,也可以直接在视图层加装饰器:
from django.utils.decorators import method_decorator from django.views import View @method_decorator(hr_permission_required, name='dispatch') class HRDashboardView(View): def get(self, request): # 业务逻辑
方案2:自定义通用角色校验装饰器(更灵活的替代方案)
Django生态里更常用的是直接写权限装饰器,不需要封装成中间件,支持动态指定角色ID,适配更多场景:
# decorators.py from functools import wraps from django.shortcuts import redirect from django.core.exceptions import PermissionDenied def role_required(allowed_role_id): def decorator(view_func): @wraps(view_func) def wrapper(request, *args, **kwargs): user = request.user # 登录校验 if not (user and user.is_authenticated and user.email): return redirect('login') # 替换为你的登录路由名 # 角色校验 if user.role_id.id != allowed_role_id: raise PermissionDenied return view_func(request, *args, **kwargs) return wrapper return decorator
使用方式和上述装饰器一致:
- 视图上直接加:
@role_required(1) - 路由层绑定:
path('edit/uploaded-files', role_required(1)(views.uploaded_files_edit))
方案3:全局中间件路由匹配规则
如果你坚持用全局注册的中间件,可以在中间件内维护受保护的路由列表,仅匹配到对应路由时才执行校验:
# middlewares.py from django.shortcuts import redirect from django.core.exceptions import PermissionDenied # 维护需要HR权限的路由前缀 PROTECTED_ROUTE_PREFIXES = [ '/edit/uploaded-files', '/hr-manage/', ] class HRMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 非保护路由直接放行 if not any(request.path.startswith(prefix) for prefix in PROTECTED_ROUTE_PREFIXES): return self.get_response(request) # 权限校验逻辑 user = request.user if not (user and user.is_authenticated and user.email): return redirect('login') if user.role_id.id != 1: raise PermissionDenied return self.get_response(request)
原有代码注意事项
- Django 1.10+之后废弃了旧的
process_request中间件写法,改用__call__方法实现 user.is_authenticated是属性不需要加()调用- 不能直接
raise 403,需要导入并抛出PermissionDenied异常,或返回HttpResponseForbidden响应 redirect参数填写你的登录路由名,空字符串会跳转到首页,不符合未登录用户跳转需求
内容的提问来源于stack exchange,提问作者Amal S R
相关产品推荐
相关产品推荐

