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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 18:06:03