Django vem com um poderoso sistema de permissão pronto para uso.

Neste artigo, veremos como atribuir permissões a usuários e grupos para autorizá-los a executar ações específicas.

Objetivos

Até o final deste artigo, você poderá:

  1. Explique como as permissões e grupos de Django funcionam
  2. Aproveite o poder do sistema de permissão interno do Django

Autenticação vs Autorização

Este artigo trata de autorização.

Em outras palavras, a autenticação responde à pergunta ‘quem é você?’ enquanto a autorização responde ‘o que você pode fazer?’.

Permissões a nível de usuário

Quando django.contrib.auth é adicionado ao INSTALLED_APPS no settings.py, o Django automaticamente cria addchangedelete e view permissions para cada modelo de Django criado.

As permissões no Django seguem a seguinte sequência de nomes:

{app}.{action}_{model_name}

Notas:

Vamos supor que temos o seguinte modelo em um aplicativo chamado “blog”:

from django.db import models


class Post(models.Model):
    title = models.CharField(max_length=400)
    body = models.TextField()

Por padrão, o Django criará as seguintes permissões:

  1. blog.add_post
  2. blog.change_post
  3. blog.delete_post
  4. blog.view_post

Você pode verificar se um usuário ( através de um objeto de usuário do Django ) tem permissões com o has_perm() método:

from django.contrib.auth import get_user_model
from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType

from blog.models import Post

content_type = ContentType.objects.get_for_model(Post)
post_permission = Permission.objects.filter(content_type=content_type)
print([perm.codename for perm in post_permission])
# => ['add_post', 'change_post', 'delete_post', 'view_post']

user = User.objects.create_user(username="test", password="test", email="[email protected]")

# Check if the user has permissions already
print(user.has_perm("blog.view_post"))
# => False

# To add permissions
for perm in post_permission:
    user.user_permissions.add(perm)

print(user.has_perm("blog.view_post"))
# => False
# Why? This is because Django's permissions do not take
# effect until you allocate a new instance of the user.

user = get_user_model().objects.get(email="[email protected]")
print(user.has_perm("blog.view_post"))
# => True

Os superusuários sempre terão permissão definida para True mesmo que a permissão não exista:

from django.contrib.auth.models import User

superuser = User.objects.create_superuser(
    username="super", password="test", email="[email protected]"
)

# Output will be true
print(superuser.has_perm("blog.view_post"))

# Output will be true even if the permission does not exists
print(superuser.has_perm("foo.add_bar"))

Um superusuário é um tipo de usuário no Django que possui todas as permissões no sistema. Sejam permissões personalizadas ou permissões criadas pelo Django, os superusuários têm acesso a todas as permissões.

Um usuário da equipe é como qualquer outro usuário do seu sistema, MAS com a vantagem adicional de poder acessar a interface do Django Admin. A interface do Django Admin é acessível apenas para superusuários e usuários da equipe.

Permissões em nível de grupo

Ter que atribuir permissões de cada vez aos usuários é tedioso e não escalável. Pode haver casos em que você deseja adicionar novas permissões a um conjunto de usuários. Aqui é onde Grupos Django entre em jogo.

O que é um grupo?

Com o Django, você pode criar grupos para usuários de classe e atribuir permissões a cada grupo; portanto, ao criar usuários, você pode simplesmente atribuir o usuário a um grupo e, por sua vez, o usuário tem todas as permissões desse grupo.

Para criar um grupo, você precisa do Group modelo de django.contrib.auth.models.

Vamos criar grupos para os seguintes papéis:

Código:

from django.contrib.auth.models import Group, User, Permission
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404

from blog.models import Post

author_group, created = Group.objects.get_or_create(name="Author")
editor_group, created = Group.objects.get_or_create(name="Editor")
publisher_group, created = Group.objects.get_or_create(name="Publisher")

content_type = ContentType.objects.get_for_model(Post)
post_permission = Permission.objects.filter(content_type=content_type)
print([perm.codename for perm in post_permission])
# => ['add_post', 'change_post', 'delete_post', 'view_post']

for perm in post_permission:
    if perm.codename == "delete_post":
        publisher_group.permissions.add(perm)

    elif perm.codename == "change_post":
        editor_group.permissions.add(perm)
        publisher_group.permissions.add(perm)
    else:
        author_group.permissions.add(perm)
        editor_group.permissions.add(perm)
        publisher_group.permissions.add(perm)

user = User.objects.get(username="test")
user.groups.add(author_group)  # Add the user to the Author group

user = get_object_or_404(User, pk=user.id)

print(user.has_perm("blog.delete_post")) # => False
print(user.has_perm("blog.change_post")) # => False
print(user.has_perm("blog.view_post")) # => True
print(user.has_perm("blog.add_post")) # => True

Execução de permissões

Além do Django Admin, as permissões geralmente são aplicadas na camada de visualização, pois o usuário é obtido do objeto de solicitação.

Para impor permissões em visualizações baseadas em classe, você pode usar o PermissãoRequiredMixin de django.contrib.auth.mixins assim:

from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import ListView

from blog.models import Post

class PostListView(PermissionRequiredMixin, ListView):
    permission_required = "blog.view_post"
    template_name = "post.html"
    model = Post

permission_requiredpode ser uma permissão única ou uma iterável permissão. Se estiver usando um iterável, o usuário deverá ter TODAS as permissões antes de poder acessar a visualização:

from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import ListView

from blog.models import Post

class PostListView(PermissionRequiredMixin, ListView):
    permission_required = ("blog.view_post", "blog.add_post")
    template_name = "post.html"
    model = Post

Para visualizações baseadas em funções, use o permission_required decorador:

from django.contrib.auth.decorators import permission_required

@permission_required("blog.view_post")
def post_list_view(request):
    return HttpResponse()

Você também pode verificar se há permissões nos modelos do Django. Com os processadores de contexto de autenticação do Django, um perms variável está disponível por padrão quando você renderiza seu modelo. O perms variável realmente contém todas as permissões no seu aplicativo Django.

Por exemplo:

{% if perms.blog.view_post %}
  {# Your content here #}
{% endif %}

Permissões no nível do modelo

Você também pode adicionar permissões personalizadas a um modelo Django através do modelo Meta opções.

Vamos adicionar um is_published bandeira para o Post modelo:

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=400)
    body = models.TextField()
    is_published = models.Boolean(default=False)

Em seguida, definiremos uma permissão personalizada chamada set_published_status:

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=400)
    body = models.TextField()
    is_published = models.Boolean(default=False)

    class Meta:
        permissions = [
            (
                "set_published_status",
                "Can set the status of the post to either publish or not"
            )
        ]

Para impor essa permissão, podemos usar o UserPassesTestMixin O Django forneceu mixin em nossa opinião, dando-nos a flexibilidade de verificar explicitamente se um usuário tem a permissão necessária ou não.

Aqui está o que uma visualização baseada em classe pode parecer que verifica se um usuário tem permissão para definir o status publicado de uma postagem:

from django.contrib.auth.mixins import UserPassesTestMixin
from django.shortcuts import render
from django.views.generic import View

from blog.models import Post

class PostListView(UserPassesTestMixin, View):
    template_name = "post_details.html"

    def test_func(self):
        return self.request.user.has_perm("blog.set_published_status")

    def post(self, request, *args, **kwargs):
        post_id = request.POST.get('post_id')
        published_status = request.POST.get('published_status')

        if post_id:
            post = Post.objects.get(pk=post_id)
            post.is_published = bool(published_status)
            post.save()

        return render(request, self.template_name)

Então, com UserPassesTestMixin, você precisa substituir o test_func método da classe e adicione seu próprio teste. Observe que o valor de retorno desse método deve sempre ser um booleano.

Permissões no nível do objeto

Se você estiver usando o Django REST Framework, ele já possui permissões no nível do objeto incorporado à classe de permissão básica. BasePermission tem has_permission, que é basicamente para visualizações de lista e has_object_permission, que verifica se o usuário tem permissão para acessar uma única instância de modelo.

Para mais informações sobre permissões no Django REST Framework, reveja Permissões no Django REST Framework.

Se você não estiver usando o Django REST Framework, para implementar permissões no nível do objeto, poderá usar terceiros, como:

Para mais pacotes relacionados a permissões, confira Pacotes Django.

Conclusão

Neste artigo, você aprendeu a adicionar permissões a um modelo Django e a verificar se há permissões. Se você tiver um número definido de tipos de usuário, poderá criar cada tipo de usuário como um grupo e fornecer as permissões necessárias ao grupo. Então, para cada usuário adicionado ao sistema e ao grupo necessário, as permissões são concedidas automaticamente a cada usuário.

Leave a Reply

Your email address will not be published. Required fields are marked *