2013-10-11 11 views
14

Django + Django Rest-framework ile geliştirmede yeni biriyim ve REST Api erişimi sağlayan bir projede çalışıyorum. Belirli bir ApiView veya Viewset'in her bir eylemine farklı bir izin atamanın en iyi uygulamasının ne olduğunu merak ediyordum.Eylem iznine göre Django rest-framework

'IsAdmin', 'IsRole1', 'IsRole2', ... gibi bazı izin sınıflarını tanımladığımı varsayalım ve tek eylemler için farklı izinler vermek istiyorum (örneğin, Rol1 kullanan bir kullanıcı oluşturabilir veya alabilir) , Role2'ye sahip bir kullanıcı güncellenebilir ve yalnızca bir Yönetici silebilir).

'Oluşturma', 'liste', 'geri al', 'güncelleştirme', 'silme' eylemlerine bir izin sınıfı atamak için sınıf tabanlı bir görünümü nasıl yapılandırabilirim? Aynı izin modeline sahip farklı tablolar için yeniden kullanılabilen bir sınıfa sahip olmak için bunu yapmaya çalışıyorum.

Belki sadece bir inç suda boğuluyorum, cevaplarınız için teşekkür ederim. RestFramework'ın sınıf tabanlı görünümleri, her bir HTTP fiili için (yani: HTTP GET => view.get() vb.) Yöntemlere sahiptir.

cevap

12

DRF'nin BasePermission uzantısını genişleten bir custom permission class oluşturabilirsiniz.

request ve view nesnelerine erişiminiz olan has_permission uygularsınız. Uygun rol için request.user'u kontrol edebilir ve True/False'u uygun şekilde döndürebilirsiniz.

Ne kadar kolay olduğuna dair iyi bir örnek için verilen IsAuthenticatedOrReadOnly sınıfına (ve diğerlerine) bakın.

Umarım bu yardımcı olur.

2

Sadece django.contrib.auth'un izinlerini, kullanıcılarını, gruplarını ve dekoratörlerini belgelendirilmiş olarak kullanmanız gerekir.

+0

django.contrib.auth en dekoratörler kullanarak ekleyebilirsiniz. Çoğunlukla HTTP yöntemlerini hiç uygulamıyorsunuz - dolayısıyla dekore edilecek hiçbir şey yok. (Sadece onları dekore etmek için onları veya gönderimi uygulamak eğlenceli değildir.) Bu durumda DRF'in kendi izin sistemini kullanmak daha iyidir. http://django-rest-framework.org/api-guide/permissions.html –

3

Django, Django Guardian'ı bir kimlik doğrulama arka planı olarak kullanan DjangoObjectPermissions adlı bir perspektif sınıfına sahiptir.

Ayarlarınızda Django koruyucu etkin olduğunda, görünümünüze yalnızca permission_classes = [DjandoObjectPermissions] ekleyin ve otomatik olarak izin kimlik doğrulaması yapar, böylece belirli bir django.contrib.auth grubu veya kullanıcısına ayarlanan izinlere göre 'CRUD' yapabilirsiniz.

Örnekle bir gist bakın.Kimlik doğrulama DRF belgelerinde

24

http://django-guardian.readthedocs.org/en/latest/installation.html destekli gibi Django Guardian ayarlayabilirsiniz

,

Not: örnek düzeyi has_object_permission yöntemi yalnızca görünüm düzeyindeki has_permission kontroller zaten geçtiyseniz adı verilecek

iznini yaklaşık user nesneyi aşağıdaki varsayalım

  • listesi: Personel sadece
  • oluşturun: herkes
  • Al: Kendi kendini veya personel
  • Güncelleme, Kısmi güncelleştirme: Kendi kendini veya personel
  • yok: personelini

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'dan çok daha sezgisel görünüyor. +1 – PritishC

1

Şahsen Django çerçevesine gelince çok deyimsel değil, bence, frankenmonster özel izinlerle bu tür nefret; Bu yüzden şu çözümle geldim - bu, @list_route ve @detail_route dekoratörlerinin nasıl çalıştığına çok benziyor. Gördüğünüz gibi

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 

: Biz yöntemler/fonksiyonlar birinci sınıf Böyle dectorator yaratıyorum tüm

İlk nesneleri olmasına güvenerek Bu,

arg listesi olarak iletilen parametrelerle süslediği işleve bir sözlük ekler. Şimdi böyle bir karışım oluşturdum: karışımları. 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 iki şey yapar; get_permissions çağrıldığında , bu eylem 'yürütüldüğü denetler ve gelen permission_classes koleksiyonunu arayacağını 'route_action_kwargs' viewset.action_method.route_action_kwargs ile ilişkili

get_serializer_class çağrıldığında, aynı yapar ve' alır

route_action_kwargs '

Şimdi yoldan 'dan' serileştirici bunu kullanabilirsiniz:

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

özel biz açıkça biz sadece yöntem üzerinde açıkça @route_action_arguments ayarlayabilirsiniz tanımlamak routse.DRF en jenerik görünümleri kullanılırken

jenerik viewsets ve yöntemleri açısından, hala her zaman bu yararlı olmayan @method_decorator

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