web-dev-qa-db-ja.com

Djangoアクションごとの残りのフレームワーク権限

私はDjango + Django Rest-frameworkを使用した開発の初心者であり、REST AP​​Iアクセスを提供するプロジェクトに取り組んでいます。特定のApiViewまたはViewsetの各アクションに異なる権限を割り当てるためのベストプラクティスは何なのかと思っていました。

'IsAdmin'、 'IsRole1'、 'IsRole2'、...などのいくつかのアクセス許可クラスを定義し、さまざまなアクセス許可を単一のアクション(たとえば、Role1のユーザーが作成または取得できるユーザー、 Role2は更新でき、管理者のみが削除できます)。

許可クラスを「作成」、「リスト」、「取得」、「更新」、「削除」アクションに割り当てるために、クラスベースのビューをどのように構成できますか?同じ許可パターンを持つ異なるテーブルで再利用できるクラスを作成するためにそうしています。

たぶん私は水のインチで溺れているだけです、あなたの返事をありがとう。

34
lWhitmore

カスタム権限クラス DRFのBasePermissionを作成できます。

has_permissionは、requestおよびviewオブジェクトにアクセスできる場所に実装します。 request.userで適切な役割を確認し、必要に応じてTrue/Falseを返すことができます。

提供されている IsAuthenticatedOrReadOnly クラス(および他のクラス)を見て、それがいかに簡単であるかを確認してください。

お役に立てば幸いです。

17
Carlton Gibson

DRFドキュメントでは、

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

userオブジェクトに関する以下の許可を想定してみましょう

  • リスト:スタッフのみ
  • 作成:誰でも
  • 取得:自分自身またはスタッフ
  • 更新、部分更新:自分自身またはスタッフ
  • 破壊:スタッフのみ

permissons.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

_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,)
_

[〜#〜]編集[〜#〜]

Django 2.0の場合、is_authenticated()を_is_authenticated_で置き換えます。メソッドは属性に変更されました。

57

私は個人的にこの種のfrankenmonsterカスタムアクセス許可を嫌っています。私の意見では、Djangoフレームワークになると、それはあまり慣用的ではないので、次の解決策を思いつきました-@list_routeおよび@detail_routeデコレーターが機能します。メソッド/関数がファーストクラスオブジェクトであるという事実に依存しています

まず、そのようなデコレータを作成しています:

decorators.py

def route_action_arguments(**kwargs):
    """
    Add arguments to the action method
    """
    def decorator(func):
        func.route_action_kwargs = kwargs
        return func
    return decorator

ご覧のとおり、関数に辞書を追加し、引数リストとして渡されたパラメーターで修飾します

今、私はそのようなミックスインを作成しました: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は2つのことを行います。 get_permissionsが呼び出されると、実行された「アクション」を確認し、route_action_kwargsに関連付けられているviewset.action_method.route_action_kwargsからpermission_classesコレクションを検索します

get_serializer_classが呼び出されると、同じことが行われ、route_action_kwargsからserializerが選択されます

それを使用する方法:

@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)

カスタムルートの場合、明示的に定義することで、メソッドに@route_action_argumentsを明示的に設定できます。

一般的なビューセットとメソッドに関しては、@method_decoratorを使用して追加できます

@method_decorator(route_action_arguments(serializer=LoginSerializer), name='create')
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet):
6
Marcin Kudzia

Djangoには、認証バックエンドとしてDjango Guardianを使用するDjangoObjectPermissionsというパーミッションクラスがあります。

設定でDjangoガーディアンをアクティブにすると、ビューにpermission_classes = [DjandoObjectPermissions]を追加するだけで、自動的に権限認証が行われるため、特定の権限セットに基づいて「CRUD」することができますDjango.contrib.authグループまたはユーザー。

Gist の例を参照してください。

Django Guardianを認証の裏付けとして設定できます http://Django-guardian.readthedocs.org/en/latest/installation.html

4
user2205363

RestFrameworkのクラスベースのビューには、HTTP動詞ごとにメソッドがあります(つまり、HTTP GET => view.get()など)。ドキュメントにあるように、Django.contrib.authの権限、ユーザー、グループ、およびデコレータを使用するだけです。

2