DRF 权限最佳实践 DRY
DRF permissions best practise DRY
目前在 DRF 中根据用户类型查看权限的最佳方法是什么?
在我的结构中有几个 user_types
,例如 TEAM_LEADER
无法创建 team
对象但可以看到 teams
的列表。这意味着对于相同的 class 视图,我想对 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)
奖金问题我的解决方案会产生任何性能问题吗?
创建自定义 Permission
class 是个好习惯。所以那部分对我来说看起来不错。我们可以讨论逻辑是应该在 Permission 中还是在 User 中(就像您所做的那样),但这没什么大不了的。
如果您想对视图中的不同端点拥有不同的权限,只需重写 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]]
@JordanKowal 的回答是正确的,但如评论中所述,
Also then i'd be repeating the permissions dict a lot ? in order to do it for every class of view right
为此您可以创建一个 mixin class。它本质上允许您做的是将一些要在多个视图中复制的 code/feature 移动到一个独立的 class 并根据您的方便从它继承。
为了扩展 Jordan 的回答,mixin class 看起来像这样:
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...
目前在 DRF 中根据用户类型查看权限的最佳方法是什么?
在我的结构中有几个 user_types
,例如 TEAM_LEADER
无法创建 team
对象但可以看到 teams
的列表。这意味着对于相同的 class 视图,我想对 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)
奖金问题我的解决方案会产生任何性能问题吗?
创建自定义 Permission
class 是个好习惯。所以那部分对我来说看起来不错。我们可以讨论逻辑是应该在 Permission 中还是在 User 中(就像您所做的那样),但这没什么大不了的。
如果您想对视图中的不同端点拥有不同的权限,只需重写 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]]
@JordanKowal 的回答是正确的,但如评论中所述,
Also then i'd be repeating the permissions dict a lot ? in order to do it for every class of view right
为此您可以创建一个 mixin class。它本质上允许您做的是将一些要在多个视图中复制的 code/feature 移动到一个独立的 class 并根据您的方便从它继承。
为了扩展 Jordan 的回答,mixin class 看起来像这样:
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...