如何在Django中创建中间件检查用户权限?含装饰器与选型疑问
Django自定义Admin面板权限控制完整方案
一、用中间件实现Admin面板全局权限校验
你不需要在中间件里嵌套@permission_required装饰器,直接在中间件中编写路径匹配+权限判断逻辑更高效,能一次性覆盖所有adminpanel请求:
1. 函数式中间件实现
写法简洁,适合逻辑简单的场景:
# middleware.py from django.shortcuts import redirect from django.urls import reverse from .models import UserAccount def admin_panel_auth_middleware(get_response): def middleware(request): # 匹配adminpanel前缀的请求(根据你的实际URL规则调整) if request.path.startswith('/adminpanel/'): # 未登录用户直接跳首页 if not request.user.is_authenticated: return redirect(reverse('home')) # 检查用户是否为管理员 try: user_account = request.user.useraccount if user_account.is_admin != 'True': return redirect(reverse('home')) except UserAccount.DoesNotExist: # 无关联UserAccount的用户直接拒绝访问 return redirect(reverse('home')) # 符合条件或非adminpanel请求,继续处理后续逻辑 response = get_response(request) return response return middleware
在settings.py的MIDDLEWARE列表中注册该中间件:
MIDDLEWARE = [ # 其他中间件... 'your_app_name.middleware.admin_panel_auth_middleware', ]
2. 类式中间件实现
结构规范,适合逻辑复杂、需要扩展的场景:
# middleware.py from django.shortcuts import redirect from django.urls import reverse from django.utils.deprecation import MiddlewareMixin from .models import UserAccount class AdminPanelAuthMiddleware(MiddlewareMixin): def process_request(self, request): if request.path.startswith('/adminpanel/'): if not request.user.is_authenticated: return redirect(reverse('home')) try: user_account = request.user.useraccount if user_account.is_admin != 'True': return redirect(reverse('home')) except UserAccount.DoesNotExist: return redirect(reverse('home')) return None
同样在settings.py中注册:
MIDDLEWARE = [ # 其他中间件... 'your_app_name.middleware.AdminPanelAuthMiddleware', ]
二、函数式vs类式中间件的核心区别
- 写法复杂度:函数式代码更精简,几行就能完成基础校验;类式需要继承
MiddlewareMixin(Django3.2+也可直接实现__call__方法),结构更规整。 - 扩展性:类式可通过继承、重写方法实现功能扩展,比如同时处理请求前校验和请求后响应;函数式逻辑变复杂后会变得臃肿,不易维护。
- 适用场景:简单的全局权限校验用函数式足够;如果需要多阶段处理、复用逻辑,类式更合适。
- 兼容性:类式兼容旧版Django,函数式是Django1.10+推荐的现代写法,更贴合函数式编程风格。
三、现有创建用户代码的优化建议
你的createNewUser函数有几个关键问题需要修正:
- 密码加密存储:直接用
create方法设置密码会明文存储,必须用set_password加密:
# 修正密码处理逻辑 user = User.objects.create(username=request.POST.get('username'), email=request.POST.get('email')) user.set_password(request.POST.get('password')) # 对密码进行加密 user.save()
- is_admin字段优化:建议将
is_admin存为布尔值(如果你的UserAccount模型用BooleanField),而非字符串:
is_admin = request.POST.get('is_admin') == 'True' useraccount = UserAccount.objects.create(user=user, is_admin=is_admin)
- 权限清理逻辑调整:确保用户保存后再清理权限,避免无效操作:
if not is_admin: user.user_permissions.clear() user.save()
四、关于@permission_required的使用说明
@permission_required适合单个视图的细粒度权限校验,但如果要给整个adminpanel的所有视图统一加校验,用中间件更高效,无需逐个视图添加装饰器。如果个别视图有特殊权限需求,可以在中间件校验通过后,再给该视图额外添加装饰器做二次校验。
内容的提问来源于stack exchange,提问作者Timur Arazmedov
相关产品推荐
相关产品推荐

