【问题标题】:Implement roles in django rest framework在 django rest 框架中实现角色
【发布时间】:2020-02-28 23:23:38
【问题描述】:

我正在构建一个应该有以下类型用户的 API

super_user - 创建/管理管理员

admin - 管理事件(模型)和事件参与者

participants - 参加活动,被管理员邀请参加活动

另外我想让每种类型的用户都有电话号码字段

tried

class SuperUser(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone_number = models.CharField(max_length=20)

class Admin(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone_number = models.CharField(max_length=20)


class Participant(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone_number = models.CharField(max_length=20)

但是直觉告诉我这是一种错误的处理方式。有人可以帮忙吗。

【问题讨论】:

  • 您的课程会进一步定制吗?现在他们看起来完全一样。与其使用 3 个不同的类来更改名称,为什么不使用一个类 Profile(或其他东西)并为用户类型设置一个字段(user_type)?这样查询所有用户会容易得多,并且可以根据 user_type 进行过滤
  • 我将如何允许超级用户创建管理员用户,管理员使用您的方法创建另一个模型(事件)@whieronymus

标签: python django django-rest-framework


【解决方案1】:

一种可能的解决方案是:

    1. 只有一个带有角色字段的用户模型,它定义了用户角色是什么。
    1. 创建一个用户组并添加每个组所需的权限。
    1. 将用户添加到用户组
    1. 使用 Django REST Framework(后来的 DRF)权限类限制访问。

解释:

  1. 仅使用一个用户模型是一种更简单、更灵活的解决方案。您可以查询所有用户,或按功能过滤(如用户角色)。标准 Django 身份验证系统需要一个 UserModel。

  2. 阅读有关 Django 用户组的更多信息。请参阅“Django Permissions Docs #1”和“Django Groups Docs #2”。 “User groups and permissions”也很有用。

您需要为每个用户角色创建一个组,并为每个组添加所需的权限。 (Django 有一个默认的模型权限,自动创建,查看给定链接上的文档)或在模型定义中手动创建所需的权限。

  1. 手动或使用脚本,通过在创建用户时定义用户的角色将用户添加到所需的组,或通过 Django 管理界面手动添加。

  2. 现在一切都应该准备好供用户角色进行有限访问了。您可以使用权限类轻松限制对 DRF 视图的访问。在“DRF Permission Docs”中查看更多信息。

让我们定义我们自己的:

from rest_framework.permissions import DjangoModelPermissions
# Using DjangoModelPermissions we can limit access by checking user permissions.

# Rights need only for CreateUpdateDelete actions.
class CUDModelPermissions(DjangoModelPermissions):
  perms_map = {
      'GET': [],
      'OPTIONS': [],
      'HEAD': ['%(app_label)s.read_%(model_name)s'],
      'POST': ['%(app_label)s.add_%(model_name)s'],
      'PUT': ['%(app_label)s.change_%(model_name)s'],
      'PATCH': ['%(app_label)s.change_%(model_name)s'],
      'DELETE': ['%(app_label)s.delete_%(model_name)s'],
  }

# Or you can inherit from BasePermission class and define your own rule for access
from rest_framework.permissions import BasePermission

class AdminsPermissions(BasePermission):
    allowed_user_roles = (User.SUPERVISOR, User.ADMINISTRATOR)

    def has_permission(self, request, view):
        is_allowed_user = request.user.role in self.allowed_user_roles
        return is_allowed_user

# ----
# on views.py

from rest_framework import generics
from .mypermissions import CUDModelPermissions, AdminsPermissions

class MyViewWithPermissions(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [CUDModelPermissions, ]
    queryset = SomeModel.objects.all()
    serializer_class = MyModelSerializer

您可以添加额外的权限类来组合访问限制。

【讨论】:

  • 您能否澄清一下您将如何处理案例 1。如果您想将特定 HTTP 方法的访问权限仅限于 X 类型的用户?
【解决方案2】:

所以在 Django 中,任何用户都有一个标志 is_superuser 对应于您的“超级用户”。所以只需使用它 - 例如User.objects.create(is_superuser=True).

对于其余部分,您可以简单地使用普通用户模型的字段来区分普通用户的子角色。

class User(AbstractBaseUser):
    can_participate_event = models.Boolean(default=False)
    can_create_event = models.Boolean(default=False)

或者

class User(AbstractBaseUser):
    permissions = models.CharField(default='')  # and populate with e.g. 'create_event,participate_event'

您可能仍需要检查视图中的所有这些字段。您添加到应用程序中的越多,它就会变得越复杂,所以我建议使用像rest-framework-roles(我是作者)或监护人这样的第三方库。

【讨论】:

    猜你喜欢
    • 2011-01-30
    • 2018-10-16
    • 1970-01-01
    • 2021-05-02
    • 2021-05-20
    • 2016-08-02
    • 2020-11-15
    • 2023-03-24
    • 1970-01-01
    相关资源
    最近更新 更多