How to get OR permissions instead of AND in REST framework

前端 未结 6 1418
遇见更好的自我
遇见更好的自我 2021-02-05 06:45

It seems that permission classes are ANDed when REST framework checks permissions. That is every permission class needs to return True for permission to be granted. This makes t

相关标签:
6条回答
  • 2021-02-05 07:01

    I think you might be able to use django-rules library here. Link

    It is a rule based engine very similar to decision trees and it can be easily integrated with permissions_class framework of DRF.

    The best part is you can perform set operations on simple permissions and create complex permissions from them.

    Example

    >>> @rules.predicate
    >>> def is_admin(user):
    ...     return user.is_staff 
    ...
    
    
    >>> @rules.predicate
    >>> def is_object_owner(user, object):
            return object.owner == user
    

    Predicates can do pretty much anything with the given arguments, but must always return True if the condition they check is true, False otherwise. Now combining these two predicates..

    is_object_editable = is_object_owner | is_admin
    

    You can use this new predicate rule is_object_editable inside your has_permissions method of permission class.

    0 讨论(0)
  • 2021-02-05 07:01

    Aside from the custom permission which is simpler approach mentioned in the earlier answer, you can also look for an existing 3rd party that handle a much complex permission handling if necessary.

    As of Feb 2016, those handling complex condition permission includes:

    • rest_condition
    • djangorestframework-composed-permissions
    0 讨论(0)
  • 2021-02-05 07:11

    One way would be to add another permission class which combines existing classes the way you want it, e.g.:

    class IsAdmin(BasePermission):
        """Allow access to admins"""
        def has_object_permission(self, request, view, obj):
            return request.user.is_admin()
    
    
    class IsOwner(BasePermission):
        """Allow access to owners"""
        def has_object_permission(self, request, view, obj):
            request.user.is_owner(obj)
    
    
    class IsAdminOrOwner(BasePermission):
        """Allow access to admins and owners"""  
        def has_object_permission(*args):
            return (IsAdmin.has_object_permission(*args) or
                    IsOwner.has_object_permission(*args))
    
    0 讨论(0)
  • 2021-02-05 07:16

    Here is a generic solution:

    from functools import reduce
    from rest_framework.decorators import permission_classes
    from rest_framework.permissions import BasePermission
    
    
    def any_of(*perm_classes):
        """Returns permission class that allows access for
           one of permission classes provided in perm_classes"""
        class Or(BasePermission):
            def has_permission(*args):
                allowed = [p.has_permission(*args) for p in perm_classes]
                return reduce(lambda x, y: x or y, allowed)
    
        return Or
    
    
    class IsAdmin(BasePermission):
        """Allow access to admins"""
    
        def has_object_permission(self, request, view, obj):
            return request.user.is_admin()
    
    
    class IsOwner(BasePermission):
        """Allow access to owners"""
    
        def has_object_permission(self, request, view, obj):
            request.user.is_owner(obj)
    
    
    """Allow access to admins and owners"""
    
    
    @permission_classes((any_of(IsAdmin, IsOwner),))
    def you_function(request):
        # Your logic
        ...
    
    0 讨论(0)
  • 2021-02-05 07:17

    You need to build your own custom http://www.django-rest-framework.org/api-guide/permissions/#custom-permissions as described in the docs.

    Something like:

    from rest_framework import permissions
    
    class IsAdminOrStaff(permissions.BasePermission):
        message = 'None of permissions requirements fulfilled.'
    
        def has_permission(self, request, view):
            return request.user.is_admin() or request.user.is_staff()
    

    Then in your view:

    permission_classes = (IsAdminOrStaff,)
    
    0 讨论(0)
  • 2021-02-05 07:25

    Now DRF allows permissions to be composed using bitwise operators: & -and- and | -or-.

    From the docs:

    Provided they inherit from rest_framework.permissions.BasePermission, permissions can be composed using standard Python bitwise operators. For example, IsAuthenticatedOrReadOnly could be written:

    from rest_framework.permissions import BasePermission, IsAuthenticated
    from rest_framework.response import Response
    from rest_framework.views import APIView
    
    class ReadOnly(BasePermission):
        def has_permission(self, request, view):
            return request.method in SAFE_METHODS
    
    class ExampleView(APIView):
        permission_classes = (IsAuthenticated|ReadOnly,)
    
        def get(self, request, format=None):
            content = {
                'status': 'request was permitted'
            }
            return Response(content)
    

    Edited: Please note there is a comma after IsAuthenticated|ReadOnly.

    0 讨论(0)
提交回复
热议问题