【问题标题】:DRF permissions best practise DRYDRF 权限最佳实践 DRY
【发布时间】:2021-08-03 22:37:45
【问题描述】:

目前根据用户类型在 DRF 中查看权限的最佳方法是什么? 在我的结构中有几个user_types,例如TEAM_LEADER 无法创建team 对象,但可以看到teams 的列表。这意味着对于同一个类视图,例如我想对 POST 和 GET 使用不同的权限。 我希望尽可能做到这一点,并且我正在尝试遵循瘦视图胖模型设计原则(也想知道这是否是 2021 年遵循的好做法)。

models.py 用于用户模型


class User(AbstractBaseUser):
    ...fields here

    objects = UserManager()

    USERNAME_FIELD = "email"

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        if perm.Meta.verbose_name=="worksite" and perm.request.method =="POST":
            if self.user_type <= self.DEPARTMENT_MANAGER:
                return True
            else:
                return False
        return True

views.py


class DashboardPermissions(BasePermission):
    message="You dont have permission for this action"

    def has_permission(self, request, view):
        return request.user.has_perm(view.Meta.verbose_name)

class ViewName(CreateAPIView):
    permission_classes = (IsAuthenticated,DashboardPermissions)
    authentication_classes = ()
    serializer_class = WorksiteSerializer
    queryset = Worksite.objects.all()
    class Meta:
        verbose_name="view_name"

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

我的解决方案会产生任何性能问题吗?

【问题讨论】:

    标签: python-3.x django rest django-rest-framework permissions


    【解决方案1】:

    @JordanKowal 的回答是正确的,但是正如 cmets 中提到的,

    然后我会重复权限字典很多吗?为了对每一类视图都做到这一点

    为此,您可以创建一个mixin class。它本质上允许您做的是将一些要在多个视图中复制的代码/功能移动到一个独立的类中,并根据您的方便从它继承。

    为了扩展 Jordan 的回答,下面是 mixin 类的样子:

    class DefaultPermissionsMixin(object):
        permissions = {
            "create": [IsAuthenticated, DashboardPermissions],
            "get": [DashboardPermissions]
        }
        
        def get_permissions(self):
            # default `get_permissions` method
            # reads `self.permission_classes`
            perms = super().get_permissions()
            if self.action in self.permissions.keys():
                return perms + [p() for p in self.permissions[self.action]]
            else:
                return perms
            
            
    class View1(CreateAPIView, DefaultPermissionsMixin):
        # ...snip...
    
    class View2(CreateAPIView, DefaultPermissionsMixin):
        # i can overwrite here per my convenience
        permissions = {
            "create": [DashboardPermissions],
            "delete": [],
        }
        # i can also define permissions the default way
        # that will be enabled on all actions
        permission_classes = [IsAuthenticated]
        # ...snip...
    

    【讨论】:

    • 这更有意义,似乎是明确的解决方案,谢谢! # ...snip.. 意味着只是假设的视图代码
    • @JesterTester 如果对您有帮助,请考虑投票或将答案标记为“已接受”。是的,#..snip.. 只是你自己的视图逻辑。
    【解决方案2】:

    创建您的自定义 Permission 类是一种很好的做法。所以那部分对我来说看起来不错。我们可以辩论逻辑应该在权限还是用户中(就像你所做的那样),但这没什么大不了的。

    如果您想对视图中的不同端点拥有不同的权限,只需覆盖 get_permissions 方法即可。

    # Inherited method from APIView
        def get_permissions(self):
            """
            Instantiates and returns the list of permissions that this view requires.
            """
            return [permission() for permission in self.permission_classes]
    

    如您所见,对于所有服务,它将从self.permission_classes 获取权限。

    要在 GET/CREATE 之间使用不同的权限,您可以创建 endpoint: [...permissions]dict 并覆盖 get_permissions 以获取与当前操作匹配的权限

    permissions = {
        "create": [P1, P2,],
        "get": [P1,]
    }
    
    def get_permissions(self):
        action = self.it_is_somewhere_in_there
        return [permission() for permissions in self.permissions[action]]
    

    【讨论】:

    • 感谢您的回答。那些 P1,P2 是不同的权限等级吗?那么我会重复权限字典很多吗?为了对每一类视图都这样做吗?
    • 是的,P1, P2 我的意思是Permission_class_1, Permission_class_2。此外,如果您有多个视图对 SAME 函数使用 SAME 权限,那么您可以创建一个自定义视图,默认这些视图并将其用作实际视图中的父视图
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    相关资源
    最近更新 更多