Permissões da estrutura REST do Django

Resumo : neste tutorial, você explorará as permissões do Django REST Framework e aprenderá como definir uma classe de permissão personalizada para o projeto de lista de tarefas.

Introdução às permissões do Django REST Framework

Django REST Framework possui algumas configurações de permissão integradas que você pode usar para proteger a API. Django REST Framework permite que você defina as permissões em três níveis:

  • Nível do projeto
  • Nível de visualização
  • Nível de modelo

Permissões em nível de projeto

As permissões em nível de projeto são definidas na configuração única do Django chamada REST_FRAMEWORKno settings.pyarquivo do projeto Django.

Por padrão, o Django REST Framework permite acesso irrestrito à API. É equivalente ao seguinte:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ]
}Linguagem de código:  Python  ( python )

Além AllowAnydas classes de permissão, o Django REST Framework também oferece outras permissões integradas em nível de projeto:

  • IsAuthenticated: apenas usuários autenticados têm acesso.
  • IsAdminUser: apenas os administradores/superusuários têm acesso.
  • IsAuthenticatedOrReadOnly: usuários não autenticados podem chamar qualquer API, mas apenas usuários autenticados precisam criar, atualizar e excluir privilégios.

Vamos usar a IsAuthenticatedclasse de permissão:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}Linguagem de código:  Python  ( python )

Se você sair como superusuário e acessar o endpoint da API que mostra todos os todos /api/v1/todos/, receberá a seguinte mensagem de erro HTTP 403 proibido:

HTTP 403 Forbidden
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "detail": "Authentication credentials were not provided."
}Linguagem de código:  Python  ( python )

O motivo é que a API requer usuário autenticado.

Vamos criar um usuário normal chamado testapiusando o site de administração http://localhost:8000/admin/1. Observe que um usuário normal não é um superusuário.

Para permitir que o usuário normal testapifaça login e logout, você precisa atualizar o URLconf no nível do projeto para criar as visualizações de login/logout:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('api.urls')),
    path("auth/", include("rest_framework.urls")), # added
]Linguagem de código:  Python  ( python )

Depois de rest_framework.urlsdefinido, você pode acessar o endpoint da API /api/v1/todos/. Uma pequena alteração é o link de login no lado direito:

Se você clicar no link Login, verá o formulário de login da seguinte forma:

Faça login na API navegável usando um usuário testapie uma senha normais. Depois de fazer login com sucesso com o testapiusuário, você verá a seguinte resposta:

Permissões no nível da visualização

Django REST Framework permite adicionar permissões no nível de visualização para um controle mais granular.

Por exemplo, você pode atualizar a TodoDetailvisualização para que apenas usuários administradores possam visualizá-la, mas usuários normais não possam acessá-la.

class TodoDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (permissions.IsAdminUser,) # added
    queryset = Todo.objects.all()
    serializer_class = TodoSerializerLinguagem de código:  Python  ( python )

A TodoDetailvisualização tem o permission_classesque é inicializado para o arquivo permissions.IsAdminUser.

Ao fazer isso, o Django REST Framework permite apenas que o usuário administrador acesse a TodoDetailvisualização, que mapeia para o endpoint da API /api/v1/todos/id.

Se você usar o testapiusuário (usuário normal) para acessar a API Todo detail, o HTTP 403 será proibido:

Para desconectar o testapiusuário, clique no link do nome de usuário e selecione clicar no link de logout:

E faça login na API navegável usando o superadministrador ( john).

Como a TodoDetailvisualização permite o acesso do superadministrador, você pode ver a resposta da API:

Permissões personalizadas

No projeto Todo, você pode restringir o acesso para que apenas os proprietários de todos possam visualizar, editar, atualizar e excluir. Mas eles não podem acessar todos os outros usuários. Além disso, o superusuário terá acesso à sua própria lista de tarefas, bem como gerenciará as tarefas de outros usuários.

Para acomodar esses requisitos de permissão, você precisa usar as permissões personalizadas do Django REST Framework.

Para definir permissão customizada, você usa a BasePermissionclasse do Django REST Framework. Aqui está o código fonte da BasePermissionclasse:

class BasePermission(metaclass=BasePermissionMetaclass):
    """
    A base class from which all permission classes should inherit.
    """

    def has_permission(self, request, view):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True

    def has_object_permission(self, request, view, obj):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return TrueLinguagem de código:  Python  ( python )

O BasePermissiontem dois métodos:

  • has_permission(self, request, view)– Retornar Truese a permissão for concedida ou Falsenão. As visualizações de lista chamarão o has_permissionmétodo para verificar as permissões.
  • has_object_permission(self, requests, view, obj)– Retornar Truese a permissão for concedida ou Falsenão. O método de visualização detalhada será chamado has_permission()primeiro. Se for aprovado, ele chamará o has_object_permission()método next para verificar as permissões.

É uma boa prática substituir ambos os métodos explicitamente para evitar configurações padrão indesejadas da classe base.

A seguir ilustramos as etapas para definir e usar uma classe de permissão personalizada no Django REST Framework:

Primeiro, defina a IsOwnerOnlyclasse que estende a BasePermissionclasse no permissions.pyarquivo:

from rest_framework import permissions


class IsOwnerOnly(permissions.BasePermission):
    def has_permission(self, request, view):
        return True

    def has_object_permission(self, request, view, obj):
        if request.user.is_superuser:
            return True

        return obj.user == request.userLinguagem de código:  Python  ( python )

O has_permissionsempre retorna True. Isso significa que qualquer usuário pode acessar a TodoListvisualização para obter todas as tarefas e criar uma nova tarefa. Observe que para restringir o acesso a todos do usuário atual, faremos isso na TodoListvisualização mais tarde.

O has_object_permissionmétodo retorna Truese o usuário atual for o superusuário ou o proprietário da tarefa.

Segundo, atualize as classes de visualização no views.pyaplicativo apipara usar a classe de permissão personalizada IsOwnerOnly:

from rest_framework import generics
from .serializers import TodoSerializer
from .permissions import IsOwnerOnly
from todo.models import Todo


class TodoList(generics.ListCreateAPIView):
    permission_classes = (IsOwnerOnly,)  # added
    queryset = Todo.objects.all()
    serializer_class = TodoSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

    # added
    def filter_queryset(self, queryset):
        queryset = queryset.filter(user=self.request.user)
        return super().filter_queryset(queryset)


class TodoDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (IsOwnerOnly,)  # added
    queryset = Todo.objects.all()
    serializer_class = TodoSerializerLinguagem de código:  Python  ( python )

Ambas TodoListas TodoDetailclasses e usam a IsOwnerOnlyclasse:

permission_classes = (IsOwnerOnly,)  # addedLinguagem de código:  Python  ( python )

Além disso, adicione o filter_querysetmétodo à TodoListclasse para retornar apenas todos do usuário atualmente autenticado:

def filter_queryset(self, queryset):
    queryset = queryset.filter(user=self.request.user)
    return super().filter_queryset(queryset)Linguagem de código:  Python  ( python )

Se você fizer login na API navegável usando o superusuário, poderá visualizar, criar, editar, atualizar e excluir todos.

Mas se você fizer login usando o usuário normal ( testapi), poderá ver que ele /api/v1/todos/retorna uma lista vazia.

Além disso, acessar o endpoint da API /api/v1/todos/1/resultará em um HTTP 403 proibido, pois o testapiusuário não tem acesso à tarefa que não pertence ao usuário:

Agora, você pode usar o testapiusuário para criar uma nova tarefa com as seguintes informações:

{
    "title": "Test API",
    "completed": false
}Linguagem de código:  Python  ( python )

Aqui está a resposta:

HTTP 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 5,
    "title": "Test API",
    "completed": false,
    "user": "testapi"
}Linguagem de código:  Python  ( python )

Faça uma solicitação HTTP GET para o /api/v1/todos/endpoint, você obterá a lista de tarefas criada pelo testapiusuário:

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "id": 5,
        "title": "Test API",
        "completed": false,
        "user": "testapi"
    }
]Linguagem de código:  Python  ( python )

Além disso, você pode testar a visualização, atualização e exclusão de tarefas com id 5 usando o testapiusuário. Deve funcionar conforme o esperado.

Baixe o código fonte do projeto

Clique no link a seguir para baixar o código-fonte do projeto:

Baixe o código fonte do projeto

Resumo

  • Django REST Framework fornece três níveis de permissão, incluindo nível de projeto, nível de visualização e nível de modelo.
  • Estenda a BasePermisssionclasse para definir permissões personalizadas de acordo com seus requisitos.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *