30

リソース「ユーザー」にアクセスするために Django REST Framework を使用しています。

ユーザー情報は個人的なものであるため、管理者でない限り、GET リクエストでシステム上のすべてのユーザーを一覧表示することは望ましくありません。

ユーザーがIDを指定してログインしている場合、必要に応じて詳細を表示して修正(PUT POST DELETE)できるようにしたいと思います。

要約すると、管理者以外のユーザーには GET メソッドを許可せず、ログインしているユーザーの情報を表示するときに GET POST DELETE PUT を許可します。

カスタム権限クラスを作成しました:

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

これはうまくいきませんでした。has_permissionいくつかのデバッグの後、最初にチェックし、次にチェックすることがわかりましたhas_object_permission。したがって、最初のハードル GET を乗り越えなければ/user/、次の GET も考慮されません/user/id

これを機能させるにはどうすればよいですか?

私はModelViewSetsを使用していました。

ただし、リスト機能を詳細と分割すると、それらに個別のアクセス許可クラスを与えることができます。

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
4

5 に答える 5

23

私は過去にカスタムパーミッションを使用してこれを行いhas_object_permission、次のようにオーバーライドしました:

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

特定のリクエスト タイプを拒否するなど、より詳細な操作を行うことができます (たとえば、すべてのユーザーに対して GET リクエストを許可するなど)。

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

次に、ビューで権限クラスを使用するように指示します。

from my_custom_permissions import MyUserPermissions

class UserView(generics.ListCreateAPIView):
    ...
    permission_classes = (MyUserPermissions, )
    ...
于 2013-09-05T22:13:28.907 に答える
10

つまずきについては、オブジェクトレベルのアクセス許可の制限に関するドキュメントには次のように記載されています。

パフォーマンス上の理由から、汎用ビューは、オブジェクトのリストを返すときに、クエリセット内の各インスタンスにオブジェクト レベルのアクセス許可を自動的に適用しません。

したがって、詳細ビューは機能しますが、リストについては、現在のユーザーに対してフィルター処理する必要があります。

于 2015-07-09T18:39:15.617 に答える
9

@will-hartの答えにもう1つ。

DRF3のドキュメントでは、

注: インスタンス レベルの has_object_permission メソッドは、ビュー レベルの has_permission チェックに合格した場合にのみ呼び出されます。

したがって、を使用するhas_permissionように指定する必要があります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

ただし、上記のコードは、ユーザーがユーザーのリストを取得しようとすると、誰にでも許可を与えます。この場合、ではなくに従って許可を与えたactionHTTP 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
于 2016-02-12T11:19:45.873 に答える