2013-10-11 3 views
14

Я новичок в разработке с Django + Django Rest-framework, и я работаю над проектом, который обеспечивает доступ REST Api. Мне было интересно, что лучше всего назначить другое разрешение для каждого действия данного ApiView или Viewset.Django rest-framework для разрешения на действие

Предположим, что я определил некоторые классы разрешений, такие как «IsAdmin», «IsRole1», «IsRole2», ... и я хочу предоставлять разные разрешения для отдельных действий (например, пользователь с Role1 может создавать или извлекать , пользователь с Role2 может обновлять, и только администратор может удалить).

Как я могу структурировать представление на основе класса, чтобы назначить класс разрешений для действий «создавать», «список», «извлекать», «обновлять», «удалять»? Я пытаюсь сделать это, чтобы иметь класс, который можно использовать повторно для разных таблиц с одинаковым шаблоном разрешения.

Возможно, я просто утонул в дюйме воды, спасибо за ваши ответы.

ответ

12

Вы можете создать custom permission class удлинители DRF BasePermission.

Вы реализуете has_permission, где у вас есть доступ к объектам и view. Вы можете проверить 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 имеет класс persmissions, называемый DjangoObjectPermissions, который использует Django Guardian в качестве аутентификационного сервера.

Когда у вас есть хранитель Django, активный в ваших настройках, вы просто добавляете permission_classes = [DjandoObjectPermissions] к вашему виду, и он автоматически выполняет авторизацию прав, поэтому вы можете «CRUD» на основе разрешения, установленного для определенной группы или пользователя django.contrib.auth.

См. Пример gist.

Вы можете установить Django Гардиан, как аутентификация при поддержке http://django-guardian.readthedocs.org/en/latest/installation.html

24

В ФПИ документации,

Примечание: Метод экземпляра уровня has_object_permission будет вызываться только если проверка has_permission зрения уровня уже прошли

Давайте предположим следующее разрешение о user объекта

  • Список: персонал только
  • Создать: кто
  • Получить: сам себя или сотрудник
  • Update, частичное обновление: сам себя или сотрудник
  • Destroy: персонал только

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

Я лично ненавижу этот вид frankenmonster пользовательских разрешений, на мой взгляд, это не очень идиоматических, когда речь идет о рамках Джанго; Итак, я придумал следующее решение - он очень похож на то, как работают декораторы @list_route и @detail_route. Мы рассчитываем на то, что методы/функции первого класса объектов

Прежде всего я создаю такую ​​dectorator:

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 

Как вы можете видеть он добавляет словарь к функции, которую он украшает параметрами, переданными как список аргументов

Теперь я создал такой mixin: 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 делает две вещи; когда get_permissions называется, он проверяет, который «действие» выполняется, и looksup коллекции permission_classes от «route_action_kwargs», связанный с viewset.action_method.route_action_kwargs

когда get_serializer_class называется, он делает то же самое, и выбирает " сериализатору»от„

теперь путь 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 явно на методе.

С точкой зрения общих viewsets и методов, мы все еще можем добавить их с помощью @method_decorator

@method_decorator(route_action_arguments(serializer=LoginSerializer), name='create') 
class UserViewSet (RouteActionArgumentsMixin, RequestContextMixin, viewsets.ModelViewSet): 
Смежные вопросы