2013-10-11 19 views
14

私はDjango + Django Restフレームワークを開発する初心者です。私はREST APIアクセスを提供するプロジェクトに取り組んでいます。私は、ApiViewまたはViewsetの各アクションに異なる権限を割り当てるのがベストプラクティスであると思っていました。アクションごとのDjango rest-framework

「IsAdmin」、「IsRole1」、「IsRole2」などのアクセス許可クラスを定義し、単一のアクションに異なるアクセス許可を与えたいとしましょう(たとえば、Role1を持つユーザーは、 Role2を持つユーザーは更新できますが、管理者だけが削除できます)。

'create'、 'list'、 'retrieve'、 'update'、 'delete'アクションに権限クラスを割り当てるために、クラスベースのビューを構成するにはどうすればよいですか? 同じ許可パターンを持つ異なるテーブルに対して再利用できるクラスを用意しようとしています。

多分私は水の中に溺れ​​ているだけかもしれません、あなたの返信に感謝します。

答えて

12

DRFのBasePermissionを拡張するcustom permission classを作成できます。

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

どれほど簡単かの良い例は、IsAuthenticatedOrReadOnlyクラス(およびその他)をご覧ください。

私は役立つことを願っています。

2

RestFrameworkのクラスベースのビューには、各HTTP動詞(HTTP GET => view.get()など)のメソッドがあります。 django.contrib.authのパーミッション、ユーザ、グループ、デコレータは文書化されているとおりに使うだけです。

+0

django.contrib.authのデコレータを使用してそれらを追加することができます。かなり頻繁にHTTPメソッドを実装しないので、飾ることはありません。 DRF独自の権限システムを使用する方がよいでしょう。 http://django-rest-framework.org/api-guide/permissions.html –

3

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

あなたの設定にDjangoガーディアンが有効になっている場合は、permission_classes = [DjandoObjectPermissions]をビューに追加するだけで自動的に許可認証が行われるため、特定のdjango.contrib.authグループまたはユーザーに設定されているアクセス許可に基づいてCRUDすることができます。

gistの例を参照してください。あなたの認証はDRFのドキュメントで

24

http://django-guardian.readthedocs.org/en/latest/installation.htmlを担保として、あなたはDjangoのガーディアンを設定することができます

注:インスタンス・レベルの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):            
     if view.action == 'retrieve':                
      return request.user.is_authenticated() and (obj == request.user or request.user.is_admin)  
     elif view.action in ['update', 'partial_update']:           
      return request.user.is_authenticated() and (obj == request.user or request.user.is_admin)  
     elif view.action == 'destroy': 
      return request.user.is_authenticated() and 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,) 
+2

'view.action'は' request.method'よりはるかに直感的です。 +1 – PritishC

1

私は個人的にはDjangoフレームワークに来るとき、それは非常に慣用的ではありません、私の意見では、frankenmonsterカスタム権限のこの種を憎みます。 私は以下の解決策を考え出しました。@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 

: 私たちはメソッド/関数は最初のクラスは、私は、このようなdectoratorを作成していますすべての

まずオブジェクトであるという事実に依存しています ミックスインを:それは今、私は、このようなミックスインを作成した引数リスト

として渡されたパラメータを飾る機能に辞書を追加します。 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が呼び出されたときに、それが実行される「アクション」チェック、およびget_serializer_classが呼び出されたとき、それは同じことを行い、 'をピックアップ

viewset.action_method.route_action_kwargsに関連付けられた「route_action_kwargs」からpermission_classesコレクションをlooksup route_action_kwargs 『

「から』シリアライザ今、私たちはそれを使用することができます方法:

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

カスタムroutseについては、我々は、明示的に、我々はちょうど方法に明示的に@route_action_argumentsを設定することができます定義されます。DRFの汎用ビューを使用した場合

ジェネリックビューセットや方法の面では、我々はまだ、常にその有用ではない @method_decoratorに

@method_decorator(route_action_arguments(serializer=LoginSerializer), name='create') 
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet): 
関連する問題