基于Django 1.11+DRF的ERP API多应用权限实现方案咨询
作为长期用Django和DRF做企业级API开发的开发者,结合你这个ERP项目的场景,我给你梳理一套落地性强的跨应用权限实现方案,都是我实际项目里验证过的思路:
一、先搭好基础:基于Django原生权限系统扩展
Django自带的django.contrib.auth已经提供了用户、组、权限的核心框架,这是跨应用权限管理的最佳起点,完全不用重复造轮子。
1. 为各应用模型定义自定义权限
每个应用的模型可以在Meta类里添加贴合业务的自定义权限,让权限颗粒度更细:
- Accounts应用(用户资料与认证):
# accounts/models.py from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): # 你的自定义字段(比如手机号、部门) class Meta: permissions = [ ("view_all_profiles", "Can view all user profiles"), ("edit_own_profile", "Can edit own user profile"), ]
- HR应用(员工管理):
# hr/models.py from django.db import models class Employee(models.Model): user = models.OneToOneField(CustomUser, on_delete=models.CASCADE) # 其他员工字段(入职日期、岗位等) class Meta: permissions = [ ("manage_employees", "Can create/edit/delete employees"), ("view_employee_details", "Can view employee details"), ]
- Payroll应用(薪资管理):
# payroll/models.py class SalarySlip(models.Model): employee = models.ForeignKey(Employee, on_delete=models.CASCADE) # 薪资字段(应发、实发、扣款等) class Meta: permissions = [ ("generate_salary_slips", "Can generate salary slips"), ("view_salary_slips", "Can view salary slips"), ("approve_salary_slips", "Can approve salary slips"), ]
这些权限会自动被Django的权限系统纳入管理,跨应用也能无缝识别。
2. 用组(Group)批量管理权限
手动给每个用户加权限效率太低,建议创建对应业务角色的组,把权限批量分配给组,再把用户加入组:
- HR管理员组:包含HR应用的所有权限 + Accounts的
view_all_profiles - 财务组:包含Payroll应用的所有权限
- 普通员工组:只有
edit_own_profile、view_employee_details(仅限自己)、view_salary_slips(仅限自己)
可以写个管理命令初始化这些组:
# accounts/management/commands/init_groups.py from django.core.management.base import BaseCommand from django.contrib.auth.models import Group, Permission class Command(BaseCommand): def handle(self, *args, **options): # 创建HR管理员组 hr_admin_group, _ = Group.objects.get_or_create(name='HR Admin') hr_perms = Permission.objects.filter(content_type__app_label='hr') accounts_perms = Permission.objects.filter(codename='view_all_profiles') hr_admin_group.permissions.add(*hr_perms, *accounts_perms) # 创建财务组 finance_group, _ = Group.objects.get_or_create(name='Finance') payroll_perms = Permission.objects.filter(content_type__app_label='payroll') finance_group.permissions.add(*payroll_perms) # 创建普通员工组 employee_group, _ = Group.objects.get_or_create(name='Employee') employee_perms = Permission.objects.filter(codename__in=[ 'edit_own_profile', 'view_employee_details', 'view_salary_slips' ]) employee_group.permissions.add(*employee_perms)
运行python manage.py init_groups就能快速初始化组和权限。
二、DRF层面的接口权限控制
因为是API项目,需要结合DRF的权限类实现接口级别的校验:
1. 全局默认权限配置
先在settings.py里设置全局默认权限,确保所有接口都经过基础校验:
# settings.py REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', 'rest_framework.permissions.DjangoModelPermissions', ] }
DjangoModelPermissions会自动对应模型的view/add/change/delete权限,加上我们自定义的权限,能覆盖大部分常规场景。
2. 自定义权限类处理精细化场景
比如“普通员工只能查看自己的薪资单”这种个性化需求,写个自定义权限类:
# payroll/permissions.py from rest_framework import permissions class IsOwnerOrAdmin(permissions.BasePermission): def has_object_permission(self, request, view, obj): # 管理员或财务可以查看所有薪资单 if request.user.has_perm('payroll.approve_salary_slips'): return True # 普通员工只能查看自己的 return obj.employee.user == request.user
然后在视图集里使用:
# payroll/views.py from rest_framework import viewsets from .models import SalarySlip from .serializers import SalarySlipSerializer from .permissions import IsOwnerOrAdmin class SalarySlipViewSet(viewsets.ModelViewSet): queryset = SalarySlip.objects.all() serializer_class = SalarySlipSerializer permission_classes = [IsOwnerOrAdmin]
3. 函数视图的权限装饰器
如果用函数式视图,直接用DRF的装饰器:
# hr/views.py from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions from .models import Employee from .serializers import EmployeeSerializer @api_view(['GET']) @permission_classes([IsAuthenticated, DjangoModelPermissions]) def employee_list(request): employees = Employee.objects.all() serializer = EmployeeSerializer(employees, many=True) return Response(serializer.data)
三、跨应用权限的统一管理与校验
1. 封装权限校验工具函数
在Accounts应用里写个工具函数,方便其他应用统一调用校验逻辑:
# accounts/utils.py def has_permission(user, perm_full_code): """检查用户是否拥有指定权限(格式:app.codename)""" return user.has_perm(perm_full_code) def is_hr_admin(user): return user.groups.filter(name='HR Admin').exists() or user.is_superuser def is_finance(user): return user.groups.filter(name='Finance').exists() or user.is_superuser
其他应用直接导入使用:
# payroll/views.py from accounts.utils import is_finance def generate_salary_slip(request): if not is_finance(request.user): return Response({'error': 'Permission denied'}, status=403) # 生成薪资单的业务逻辑...
2. 用Django Admin统一管理
Django Admin默认已经支持跨应用管理用户、组、权限,权限会按应用分类显示,直接在Admin里就能给用户/组分配不同应用的权限,操作非常直观。
四、实用落地技巧
- Django信号自动分配默认组:监听用户创建事件,自动给新用户分配普通员工组,减少手动操作:
# accounts/signals.py from django.db.models.signals import post_save from django.dispatch import receiver from .models import CustomUser from django.contrib.auth.models import Group @receiver(post_save, sender=CustomUser) def assign_default_group(sender, instance, created, **kwargs): if created: employee_group = Group.objects.get(name='Employee') instance.groups.add(employee_group)
记得在accounts/apps.py里注册信号:
# accounts/apps.py from django.apps import AppConfig class AccountsConfig(AppConfig): name = 'accounts' def ready(self): import accounts.signals
- 查看权限分配情况:在Django shell里可以快速验证权限:
python manage.py shell >>> from django.contrib.auth.models import User >>> user = User.objects.get(username='test') >>> user.has_perm('hr.manage_employees') >>> user.groups.all()
内容的提问来源于stack exchange,提问作者Philip Mutua

