Jos*_*iño 46 python django permissions rest django-rest-framework
我正在使用Django REST Framework编写API,我想知道在使用基于类的视图时是否可以为每个方法指定权限.
阅读我看到的文档,如果您正在编写基于函数的视图,只需使用@permission_classes装饰器覆盖您想要使用权限保护的视图的功能,这很容易.不过,我不明白的方式使用与CBVS时做同样的APIView课,因为那时我指定用满级的权限permission_classes属性,但将被再应用到所有类方法(get,post,put... ).
那么,是否可以使用CBV编写API视图,并为视图类的每个方法指定不同的权限?
jam*_*mes 47
我在使用CBV时遇到了同样的问题,因为我有相当复杂的权限逻辑,具体取决于请求方法.
我想出的解决方案是使用本页底部列出的第三方'rest_condition'应用程序
http://www.django-rest-framework.org/api-guide/permissions
https://github.com/caxap/rest_condition
我只是拆分权限流逻辑,以便每个分支都运行,具体取决于请求方法.
from rest_condition import And, Or, Not
class MyClassBasedView(APIView):
permission_classes = [Or(And(IsReadOnlyRequest, IsAllowedRetrieveThis, IsAllowedRetrieveThat),
And(IsPostRequest, IsAllowedToCreateThis, ...),
And(IsPutPatchRequest, ...),
And(IsDeleteRequest, ...)]
Run Code Online (Sandbox Code Playgroud)
因此,"或"根据请求方法确定权限的哪个分支应运行,并且"And"包含与接受的请求方法相关的权限,因此所有权限都必须通过才能被授予权限.您还可以在每个流中混合使用"或","和"和"不"来创建更复杂的权限.
运行每个分支的权限类看起来像这样,
class IsReadyOnlyRequest(permissions.BasePermission):
def has_permission(self, request, view):
return request.method in permissions.SAFE_METHODS
class IsPostRequest(permissions.BasePermission):
def has_permission(self, request, view):
return request.method == "POST"
... #You get the idea
Run Code Online (Sandbox Code Playgroud)
Kev*_*one 45
权限适用于整个View类,但您可以在授权决策中考虑请求的各个方面(如GET或POST等方法).
以内置IsAuthenticatedOrReadOnly示例为例:
SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
class IsAuthenticatedOrReadOnly(BasePermission):
"""
The request is authenticated as a user, or is a read-only request.
"""
def has_permission(self, request, view):
if (request.method in SAFE_METHODS or
request.user and
request.user.is_authenticated()):
return True
return False
Run Code Online (Sandbox Code Playgroud)
rob*_*bin 15
2020 年 3 月 30 日更新:我的原始解决方案仅修补对象权限,而不是请求权限。我在下面包含了一个更新,以使这项工作也适用于请求权限。
我知道这是一个老问题,但我最近遇到了同样的问题并想分享我的解决方案(因为接受的答案并不是我所需要的)。@GDorn 的回答让我走上了正确的轨道,但它只适用于ViewSets,因为self.action
我已经解决了它创建我自己的装饰器:
def method_permission_classes(classes):
def decorator(func):
def decorated_func(self, *args, **kwargs):
self.permission_classes = classes
# this call is needed for request permissions
self.check_permissions(self.request)
return func(self, *args, **kwargs)
return decorated_func
return decorator
Run Code Online (Sandbox Code Playgroud)
permission_classes不像内置装饰器那样在函数上设置属性,我的装饰器包装调用并在被调用的视图实例上设置权限类。这样,法线get_permissions()不需要任何更改,因为这仅依赖于self.permission_classes.
要使用请求权限,我们确实需要check_permission()从装饰器调用,因为它最初是在修补属性initial()之前调用的permission_classes。
注意通过装饰器设置的权限是唯一调用对象权限的权限,但对于请求权限,它们是类范围权限的补充,因为它们总是在调用请求方法之前进行检查。如果只想为每个方法指定所有权限,请permission_classes = []在类上设置。
示例用例:
from rest_framework import views, permissions
class MyView(views.APIView):
permission_classes = (permissions.IsAuthenticatedOrReadOnly,) # used for default APIView endpoints
queryset = MyModel.objects.all()
serializer_class = MySerializer
@method_permission_classes((permissions.IsOwnerOfObject,)) # in addition to IsAuthenticatedOrReadOnly
def delete(self, request, id):
instance = self.get_object() # ...
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助遇到同样问题的人!
GDo*_*orn 10
我遇到了这个问题,真的很想使用@permission_classes装饰器来标记一些具有特定权限的自定义视图方法。我最终想出了一个mixin:
class PermissionsPerMethodMixin(object):
def get_permissions(self):
"""
Allows overriding default permissions with @permission_classes
"""
view = getattr(self, self.action)
if hasattr(view, 'permission_classes'):
return [permission_class() for permission_class in view.permission_classes]
return super().get_permissions()
Run Code Online (Sandbox Code Playgroud)
一个示例用例:
from rest_framework.decorators import action, permission_classes # other imports elided
class MyViewset(PermissionsPerMethodMixin, viewsets.ModelViewSet):
permission_classes = (IsAuthenticatedOrReadOnly,) # used for default ViewSet endpoints
queryset = MyModel.objects.all()
serializer_class = MySerializer
@action(detail=False, methods=['get'])
@permission_classes((IsAuthenticated,)) # overrides IsAuthenticatedOrReadOnly
def search(self, request):
return do_search(request) # ...
Run Code Online (Sandbox Code Playgroud)
小智 7
我遇到了类似的问题。
我想允许未经身份验证的 POST,但不允许未经身份验证的 GET。
未经身份验证的公众成员可以提交项目,但只有经过身份验证的管理员用户才能检索提交的项目列表。
因此,我为 POST 构建了一个自定义权限类 - UnauthenticatedPost- ,然后将权限类列表设置为IsAuthentictaed或UnauthenticatedPost。
注意我只允许通过设置允许的方法来获取和发布http_method_names = ['get', 'post']。
from django.http import HttpResponse
from rest_framework import viewsets
from rest_framework.permissions import BasePermission, IsAuthenticated
from MyAPI.serializers import MyAPISerializer
from MyAPI.models import MyAPI
class UnauthenticatedPost(BasePermission):
def has_permission(self, request, view):
return request.method in ['POST']
class MyAPIViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated|UnauthenticatedPost]
queryset = MyAPI.objects.all().order_by('-TimeSubmitted')
serializer_class = MyAPISerializer
http_method_names = ['get', 'post']
Run Code Online (Sandbox Code Playgroud)
如果你使用ViewSets 或ModelViewSets,我认为覆盖get_permissions就可以了。
看看djoser如何处理这个问题。
例子:
class UserViewSet(viewsets.ModelViewSet):
permission_classes = settings.PERMISSIONS.user # default
def get_permissions(self):
if self.action == "activation": # per action
self.permission_classes = settings.PERMISSIONS.activation
return super().get_permissions()
@action(["post"], detail=False) # action
def activation(self, request, *args, **kwargs):
pass
Run Code Online (Sandbox Code Playgroud)
小智 6
这个问题是关于实例的,但是对于任何登陆这里寻找使用装饰器的APIView每个方法的权限覆盖的人:@actionViewSets
class SandwichViewSet(ModelViewSet):
permission_classes = [IsAuthenticated]
@action(..., permission_classes=[CanSeeIngredients])
def retrieve__ingredients(self, request):
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20079 次 |
| 最近记录: |