2013-09-05 32 views
21

Tôi đang sử dụng Khung công tác REST Django để truy cập tài nguyên 'người dùng'.Quyền đối tượng cấp khung đối tượng Django REST

Khi thông tin người dùng là cá nhân, tôi không muốn yêu cầu GET liệt kê mọi người dùng trên hệ thống, KHÔNG BAO GIỜ họ là quản trị viên.

Nếu người dùng chỉ định id của họ và họ đã đăng nhập, tôi muốn họ có thể xem chi tiết của họ và sửa đổi chúng (PUT POST DELETE) nếu được yêu cầu.

Tóm lại, không cho phép phương thức GET cho bất kỳ ai không phải là quản trị viên và cho phép GET POST DELETE PUT trên người dùng đã đăng nhập khi xem thông tin của họ.

vì vậy tôi tạo ra các lớp cho phép tùy chỉnh:

class UserPermissions(permissions.BasePermission): 
    """ 
    Owners of the object or admins can do anything. 
    Everyone else can do nothing. 
""" 

    def has_permission(self, request, view): 
     # if admin: True otherwise False 
    def has_object_permission(self, request, view, obj): 
     # if request.user is the same user that is contained within the obj then allow 

này đã không làm việc. Sau khi một số gỡ lỗi tôi thấy rằng nó kiểm tra has_permission đầu tiên, THEN kiểm tra has_object_permission. Vì vậy, nếu chúng ta không vượt qua rào cản đầu tiên GET/user /, thì nó thậm chí sẽ không xem xét GET/user/id tiếp theo.

vậy Tóm lại, có ai biết tôi sẽ làm thế nào để làm việc này không?

Cảm ơn :)

EDIT:

Tôi đã sử dụng ModelViewSets, mà không có vấn đề này như tôi đã mô tả.

Nhưng nếu bạn chia các chức năng Danh sách với các chi tiết sau đó bạn có thể cung cấp cho họ các lớp học phép riêng biệt:

class UserList(generics.ListCreateAPIView): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 
    permission_classes=(UserPermissionsAll,) 

class UserDetail(generics.RetrieveUpdateDestroyAPIView): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 
    permission_classes=(UserPermissionsObj,) 

class UserPermissionsAll(permissions.BasePermission): 
""" 
Owners of the object or admins can do anything. 
Everyone else can do nothing. 
""" 

    def has_permission(self, request, view): 
     if request.user.is_staff: 
      return True 
     else: 
      return False 

class UserPermissionsObj(permissions.BasePermission): 
""" 
Owners of the object or admins can do anything. 
Everyone else can do nothing. 
""" 

    def has_object_permission(self, request, view, obj): 
     if request.user.is_staff: 
      return True 

     return obj == request.user 
+0

Giải pháp bên dưới từ Trình lập hóa chất sẽ hoạt động với 'bộ đếm '. – jfunk

Trả lời

18

Tôi đã làm điều này trong quá khứ bằng một sự cho phép tùy chỉnh và ghi đè has_object_permission như sau:

from rest_framework import permissions 


class MyUserPermissions(permissions.BasePermission): 
    """ 
    Handles permissions for users. The basic rules are 

    - owner may GET, PUT, POST, DELETE 
    - nobody else can access 
    """ 

    def has_object_permission(self, request, view, obj): 

     # check if user is owner 
     return request.user == obj 

Bạn có thể làm một số điều chi tiết hơn như từ chối các loại theo yêu cầu cụ thể (ví dụ để cho phép một yêu cầu GET cho tất cả người dùng):

class MyUserPermissions(permissions.BasePermission): 

    def has_object_permission(self, request, view, obj): 

     # Allow get requests for all 
     if request.method == 'GET': 
      return True 
     return request.user == obj 

Sau đó, theo quan điểm của bạn, bạn nói cho nó để sử dụng lớp điều khoản:

from my_custom_permissions import MyUserPermissions 

class UserView(generics.ListCreateAPIView): 
    ... 
    permission_classes = (MyUserPermissions,) 
    ... 
10

tôi có nhu cầu tương tự. Cho phép gọi ứng dụng của tôi x. Đây là những gì tôi nghĩ ra.

Đầu tiên, đặt điều này trong x/viewsets.py:

# viewsets.py 
from rest_framework import mixins, viewsets 

class DetailViewSet(
    mixins.CreateModelMixin, 
    mixins.RetrieveModelMixin, 
    mixins.UpdateModelMixin, 
    mixins.DestroyModelMixin, 
    viewsets.GenericViewSet): 
    pass 

class ReadOnlyDetailViewSet(
    mixins.RetrieveModelMixin, 
    viewsets.GenericViewSet): 
    pass 

class ListViewSet(
    mixins.ListModelMixin, 
    viewsets.GenericViewSet): 
    pass 

Sau đó, trong x/permissions.py:

# permissions.py 
from rest_framework import permissions 

class UserIsOwnerOrAdmin(permissions.BasePermission): 
    def has_permission(self, request, view): 
     return request.user and request.user.is_authenticated() 

    def check_object_permission(self, user, obj): 
     return (user and user.is_authenticated() and 
      (user.is_staff or obj == user)) 

    def has_object_permission(self, request, view, obj): 
     return self.check_object_permission(request.user, obj) 

Sau đó, trong x/views.py:

# views.py 
from x.viewsets import DetailViewSet, ListViewSet 
from rest_framework import permissions 

class UserDetailViewSet(DetailViewSet): 
    queryset = User.objects.all() 
    serializer_class = UserDetailSerializer 
    permission_classes = (UserIsOwnerOrAdmin,) 

class UserViewSet(ListViewSet): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 
    permission_classes (permissions.IsAdminUser,) 

Bằng cách này, nhận thấy rằng bạn có thể sử dụng một differe nt serializer cho hai bộ quan sát này, có nghĩa là bạn có thể hiển thị các thuộc tính khác nhau trong chế độ xem list so với chế độ xem retrieve! Ví dụ:

# serializers.py 
class UserSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = User 
     fields = ('username', 'url',) 

class UserDetailSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = User 
     fields = ('url', 'username', 'groups', 'profile', 'password',) 
     write_only_fields = ('password',) 

Sau đó, trong x/urls.py:

# urls.py 
from x import views 
from rest_framework import routers 

router = routers.DefaultRouter() 
router.register(r'users', views.UserViewSet) 
router.register(r'users', views.UserDetailViewSet) 

... 

Tôi đã nhẹ ngạc nhiên rằng router chấp nhận cùng một khuôn mẫu hai lần, nhưng nó xuất hiện để làm việc.

Caveat đọc có: Tôi đã xác nhận điều này tất cả các công trình thông qua trình duyệt API, nhưng tôi đã không cố gắng cập nhật qua API được nêu ra.

6

Đối với những va vấp-upons, các documentation dưới giới hạn của giấy phép cấp đối tượng nói:

For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects. 

Vì vậy, chi tiết xem sẽ làm việc nhưng đối với danh sách, bạn sẽ cần phải filter chống lại người sử dụng hiện nay.

6

Chỉ một điều nữa là câu trả lời của @ will-hart.

Trong tài liệu DRF3,

Lưu ý: Phương pháp dụ cấp has_object_permission sẽ chỉ được gọi là nếu kiểm tra has_permission xem cấp đã thông qua

Do đó, has_permission nên được chỉ định sử dụng has_object_permission.

from rest_framework import permissions 

class MyUserPermissions(permissions.BasePermission): 

    def has_permission(self, request, view): 
     return True 

    def has_object_permission(self, request, view, obj): 
     return request.user == obj 

Tuy nhiên, trên mã sẽ cho phép bất cứ ai khi người dùng cố gắng để có được danh sách người dùng. Trong trường hợp này, tốt hơn là hãy cấp quyền theo action, không phải là HTTP method.

from rest_framework import permissions 

def has_permission(self, request, view): 
    if request.user.is_superuser: 
     return True 
    elif view.action == 'retrieve': 
     return True 
    else: 
     return False 

def has_object_permission(self, request, view, obj): 
    if request.user.is_superuser: 
     return True 
    elif view.action == 'retrieve': 
     return obj == request.user or request.user.is_staff 
Các vấn đề liên quan