Python 每个动作权限的 Django 休息框架
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19313314/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Django rest-framework per action permission
提问by lWhitmore
I'm a newbie in developing with Django + Django Rest-framework and I'm working on a project that provides REST Api access. I was wondering what is the best practice to assign a different permission to each action of a given ApiView or Viewset.
我是使用 Django + Django Rest-framework 进行开发的新手,我正在开发一个提供 REST Api 访问的项目。我想知道为给定 ApiView 或 Viewset 的每个操作分配不同权限的最佳实践是什么。
Let's suppose I defined some permissions classes such as 'IsAdmin', 'IsRole1', 'IsRole2', ..., and I want to grant different permissions to the single actions (e.g. a user with Role1 can create or retrieve, a user with Role2 can update, and only an Admin can delete).
假设我定义了一些权限类,例如“IsAdmin”、“IsRole1”、“IsRole2”……,并且我想为单个操作授予不同的权限(例如,具有 Role1 的用户可以创建或检索,具有Role2 可以更新,只有 Admin 可以删除)。
How can I structure a class based view in order to assign a permission class to the 'create', 'list', 'retrieve', 'update', 'delete' actions? I'm trying to do so to have a class that can be reused for different tables that have the same permission pattern.
如何构建基于类的视图,以便为“创建”、“列表”、“检索”、“更新”、“删除”操作分配权限类?我试图这样做是为了拥有一个可以重用于具有相同权限模式的不同表的类。
Maybe I'm just drowning in an inch of water, thank you for your replies.
可能我只是淹死在一寸水里,谢谢你的回复。
采纳答案by Carlton Gibson
You can create a custom permission classextending DRF's BasePermission
.
您可以创建一个自定义权限类扩展 DRF 的BasePermission
.
You implement has_permission
where you have access to the request
and view
objects. You can check request.user
for the appropriate role and return True
/False
as appropriate.
您可以has_permission
在可以访问request
和view
对象的地方实现。您可以检查request.user
适当的角色并根据需要返回True
/ False
。
Have a look at the provided IsAuthenticatedOrReadOnlyclass (and others) for a good example of how easy it is.
查看提供的IsAuthenticatedOrReadOnly类(和其他类),了解它是多么容易的一个很好的例子。
I hope that helps.
我希望这有帮助。
回答by bruno desthuilliers
RestFramework's class-based views have methods for each HTTP verb (ie : HTTP GET => view.get() etc). You just have to use django.contrib.auth's permissions, users, groups and decorators as documented.
RestFramework 的基于类的视图具有针对每个 HTTP 动词的方法(即:HTTP GET => view.get() 等)。您只需要按照文档中的说明使用 django.contrib.auth 的权限、用户、组和装饰器。
回答by Carlton Gibson
Django has a persmissions class called DjangoObjectPermissions which uses Django Guardian as an authentication backend.
Django 有一个名为 DjangoObjectPermissions 的权限类,它使用 Django Guardian 作为身份验证后端。
When you have Django guardian active in your settings you just add permission_classes = [DjandoObjectPermissions]
to your view and it does permission authentication automatically, so you can 'CRUD' based on the permission set to a particular django.contrib.auth
group or user.
当您在设置中激活 Django Guardian 时,您只需将其添加permission_classes = [DjandoObjectPermissions]
到您的视图中,它就会自动进行权限验证,因此您可以根据为特定django.contrib.auth
组或用户设置的权限“CRUD” 。
See a gistwith an example.
查看带有示例的要点。
You can set Django Guardian as your authentication backed http://django-guardian.readthedocs.org/en/latest/installation.html
您可以将 Django Guardian 设置为您的身份验证支持http://django-guardian.readthedocs.org/en/latest/installation.html
回答by Chemical Programmer
In DRF documentation,
在 DRF 文档中,
Note: The instance-level has_object_permission method will only be called if the view-level has_permission checks have already passed
注意:实例级 has_object_permission 方法只有在视图级 has_permission 检查已经通过时才会被调用
Let's assume following permission about user
object
让我们假设以下关于user
对象的权限
- List : staff only
- Create : anyone
- Retrieve : own self or staff
- Update, Partial update : own self or staff
- Destroy : staff only
- 名单:仅限员工
- 创建:任何人
- 检索:自己或员工
- 更新,部分更新:自己或员工
- 销毁:仅限员工
permissons.py
权限.py
from rest_framework import permissions
class UserPermission(permissions.BasePermission):
def has_permission(self, request, view):
if view.action == 'list':
return request.user.is_authenticated() and request.user.is_admin
elif view.action == 'create':
return True
elif view.action in ['retrieve', 'update', 'partial_update', 'destroy']:
return True
else:
return False
def has_object_permission(self, request, view, obj):
# Deny actions on objects if the user is not authenticated
if not request.user.is_authenticated():
return False
if view.action == 'retrieve':
return obj == request.user or request.user.is_admin
elif view.action in ['update', 'partial_update']:
return obj == request.user or request.user.is_admin
elif view.action == 'destroy':
return request.user.is_admin
else:
return False
views.py
视图.py
from .models import User
from .permissions import UserPermission
from .serializers import UserSerializer
from rest_framework import viewsets
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (UserPermission,)
EDIT
编辑
For Django 2.0 replace is_authenticated()
with is_authenticated
. The method has been turned into an attribute.
对于 Django 2.0 替换is_authenticated()
为is_authenticated
. 方法已经变成了一个属性。
回答by Marcin Kudzia
I personally hate this kind of frankenmonster custom permissions, in my opinion, it's not very idiomatic when it comes to Django framework;
So I came up with the following solution - it's very similar to how @list_route
and @detail_route
decorators work.
We are relying on the fact that the methods/functions are first class objects
我个人很讨厌这种 frankenmonster 自定义权限,在我看来,对于 Django 框架来说,这不是很习惯;所以我想出了以下解决方案 - 它@list_route
与@detail_route
装饰器的工作方式非常相似。我们依赖于方法/函数是一流对象这一事实
First of all I'm creating such decorator:
首先,我正在创建这样的装饰器:
decorators.py
装饰器.py
def route_action_arguments(**kwargs):
"""
Add arguments to the action method
"""
def decorator(func):
func.route_action_kwargs = kwargs
return func
return decorator
As you can see it adds a dictionary to the function it decorates with parameters passed as arg list
正如你所看到的,它向函数中添加了一个字典,它使用作为 arg 列表传递的参数进行装饰
Now I created such mixin: mixins.py
现在我创建了这样的 mixin: mixins.py
class RouteActionArgumentsMixin (object):
"""
Use action specific parameters to
provide:
- serializer
- permissions
"""
def _get_kwargs(self):
action = getattr(self, 'action')
if not action:
raise AttributeError
print('getting route kwargs for action:' + action)
action_method = getattr(self, action)
kwargs = getattr(action_method, 'route_action_kwargs')
print(dir(kwargs))
return kwargs
def get_serializer_class(self):
try:
kwargs = self._get_kwargs()
return kwargs['serializer']
except (KeyError, AttributeError):
return super(RouteActionArgumentsMixin, self).get_serializer_class()
def get_permissions(self):
try:
kwargs = self._get_kwargs()
return kwargs['permission_classes']
except (KeyError, AttributeError):
return super(RouteActionArgumentsMixin, self).get_permissions()
Mixin does two things;
when get_permissions
is called, it checks which 'action' is executed, and looksup the permission_classes collection from the route_action_kwargs
associated with the viewset.action_method.route_action_kwargs
Mixin 做了两件事;当get_permissions
被调用时,它检查执行了哪个“动作”,并从route_action_kwargs
与viewset.action_method.route_action_kwargs
when get_serializer_class
is called, it does the same and picks the serializer
from route_action_kwargs
当get_serializer_class
被调用时,它会做同样的事情并serializer
从route_action_kwargs
Now the way we can use it:
现在我们可以使用它的方式:
@method_decorator(route_action_arguments(serializer=LoginSerializer), name='create')
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet):
"""
User and profile managment viewset
"""
queryset = User.objects.all()
serializer_class = UserSerializer
@list_route(methods=['post'])
@route_action_arguments(permission_classes=(AllowAny,), serializer=LoginSerializer)
def login(self, request):
serializer = self.get_serializer_class()(data=request.data)
For custom routs we define explicitly we can just set the @route_action_arguments
explicitly on the method.
对于我们明确定义的自定义路由,我们可以@route_action_arguments
在方法上明确设置。
In terms of generic viewsets and methods, we can still add them using the
@method_decorator
在通用视图集和方法方面,我们仍然可以使用
@method_decorator
@method_decorator(route_action_arguments(serializer=LoginSerializer), name='create')
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet):