Права доступа в Django
Django поставляется с мощной системой разрешений, готовой к использованию.
В этой статье мы рассмотрим, как назначить разрешения пользователям и группам, чтобы разрешить им выполнять определенные действия.
Цели
К концу этой статьи вы сможете:
- Объяснить, как работают разрешения и группы Django
- Использовать возможности встроенной системы разрешений Django
Аутентификация против авторизации
Эта статья посвящена авторизации.
- Аутентификация - это процесс подтверждения наличия у пользователя доступа к системе. Как правило, для аутентификации пользователя используются имя пользователя/адрес электронной почты и пароль.
- Авторизация: относится к тому, что "аутентифицированный" пользователь может делать в системе.
Иными словами, аутентификация отвечает на вопрос "кто вы?", а авторизация - на вопрос "что вы можете сделать?'.
Разрешения на уровне пользователя
Когда django.contrib.auth
добавляется к параметру INSTALLED_APPS
в settings.py файл, Django автоматически создает add
, change
, delete
и view
разрешений для каждой создаваемой модели Django.
Разрешения в Django следуют следующей последовательности присвоения имен:
{app}.{action}_{model_name}
Примечания:
app
это название приложения Django, в котором находится соответствующая модельaction
: являетсяadd
,change
,delete
, илиview
model_name
: это название модели в нижнем регистре
Давайте предположим, что у нас есть следующая модель в приложении под названием "блог":
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=400)
body = models.TextField()
По умолчанию Django создаст следующие разрешения:
blog.add_post
blog.change_post
blog.delete_post
blog.view_post
Затем вы можете проверить, есть ли у пользователя (через объект пользователя Django) разрешения, с помощью метода has_perm()
:
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="test@user.com")
# 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="test@user.com")
print(user.has_perm("blog.view_post"))
# => True
Для суперпользователей всегда будет установлено разрешение True
, даже если это разрешение не существует:
from django.contrib.auth.models import User
superuser = User.objects.create_superuser(
username="super", password="test", email="super@test.com"
)
# 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"))
Суперпользователь - это тип пользователя в Django, который обладает всеми разрешениями в системе. Будь то пользовательские разрешения или разрешения, созданные в Django, суперпользователи имеют доступ ко всем разрешениям.
Пользователь staff ничем не отличается от любого другого пользователя в вашей системе, но с дополнительным преимуществом - возможностью доступа к интерфейсу администратора Django. Интерфейс администратора Django доступен только для суперпользователей и штатных пользователей.
Разрешения на уровне группы
Необходимость каждый раз назначать разрешения пользователям утомительна и не поддается масштабированию. В некоторых случаях может потребоваться добавить новые разрешения для группы пользователей. Вот тут-то и вступают в игру группы Django.
Что такое группа?
- Определение на английском языке: Группа - это набор объектов, которые классифицируются вместе.
- Определение Django: Групповые модели - это общий способ категоризации пользователей, позволяющий применять к ним разрешения или какой-либо другой ярлык. Пользователь может принадлежать к любому количеству групп.
С помощью Django вы можете создавать группы для классификации пользователей и назначать разрешения каждой группе, поэтому при создании пользователей вы можете просто назначить пользователя группе, и, в свою очередь, пользователь получит все разрешения от этой группы.
Чтобы создать группу, вам понадобится модель Group
из django.contrib.auth.models
.
Давайте создадим группы для следующих ролей:
Author
: Можно просматривать и добавлять записиEditor
: Может просматривать, добавлять и редактировать записиPublisher
: Может просматривать, добавлять, редактировать и удалять записи
Код:
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
Принудительное выполнение разрешений
Помимо администратора Django, разрешения обычно применяются на уровне представления, поскольку пользователь получает их из объекта запроса.
Для принудительного применения разрешений в представлениях на основе классов вы можете использовать PermissionRequiredMixin из django.contrib.auth.mixins
следующим образом:
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_required
может быть как одно разрешение, так и набор итерационных разрешений. При использовании итерационного параметра пользователь должен иметь ВСЕ разрешения, прежде чем он сможет получить доступ к представлению:
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
Для представлений на основе функций используйте permission_required
декоратор:
from django.contrib.auth.decorators import permission_required
@permission_required("blog.view_post")
def post_list_view(request):
return HttpResponse()
Вы также можете проверить наличие разрешений в ваших шаблонах Django. С помощью контекстных процессоров аутентификации в Django переменная perms доступна по умолчанию при визуализации вашего шаблона. Переменная perms
фактически содержит все разрешения в вашем приложении Django.
Например:
{% if perms.blog.view_post %}
{# Your content here #}
{% endif %}
Разрешения на уровне модели
Вы также можете добавить пользовательские разрешения к модели Django с помощью параметров model Meta.
Давайте добавим флаг is_published
к модели Post
:
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=400)
body = models.TextField()
is_published = models.Boolean(default=False)
Далее мы установим пользовательское разрешение с именем 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"
)
]
Чтобы обеспечить соблюдение этого разрешения, мы можем использовать UserPassesTestMixin
, на наш взгляд, предоставленный Django mixin, что дает нам возможность явно проверять, есть ли у пользователя требуемое разрешение или нет.
Вот как может выглядеть представление на основе классов, которое проверяет, есть ли у пользователя разрешение на установку статуса публикации для записи:
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)
Итак, с помощью UserPassesTestMixin
вам нужно переопределить метод test_func
класса и добавить свой собственный тест. Обратите внимание, что возвращаемое значение этого метода всегда должно быть логическим.
Разрешения на уровне объекта
Если вы используете фреймворк Django REST, у него уже есть разрешения объектного уровня, встроенные в базовый класс разрешений. BasePermission
имеет has_permission
, который в основном предназначен для просмотра списков и has_object_permission
, который проверяет, есть ли у пользователя разрешение на доступ к одному экземпляру модели.
Подробнее о разрешениях в Django REST Framework читайте в разделе Разрешения в Django REST Framework.
Если вы не используете Django REST Framework, то для реализации разрешений на уровне объекта вы можете использовать стороннюю платформу, например:
Дополнительные пакеты, связанные с правами доступа, смотрите в разделе Пакеты Django.
Заключение
В этой статье вы узнали, как добавить разрешения к модели Django и проверить их наличие. Если у вас есть определенное количество типов пользователей, вы можете создать каждый тип пользователя как группу и предоставить группе необходимые разрешения. Затем каждому пользователю, добавленному в систему и в требуемую группу, автоматически предоставляются соответствующие разрешения.
Вернуться на верх