Разрешения и группы (Permissions & Groups)

Курс по Django: https://stepik.org/a/183363

Архив проекта: 72_sitewomen.zip

На предыдущем занятии мы с вами расширили стандартную модель User, создав свою собственную. Причем, благодаря наследованию новой модели от класса AbstractUser, в ней содержатся все стандартные поля и внешние ключи прежней модели. Если открыть файл users/migrations/0001_initial.py, то увидим внешние ключи с именами:

  • groups – группы, которым принадлежит пользователь;
  • user_permissions – разрешения, которые имеются у пользователя.

Как раз об этих группах и разрешениях и пойдет речь на этом занятии. Подробная документация о них приведена на следующей странице:

https://docs.djangoproject.com/en/4.2/topics/auth/default/#permissions-and-authorization

Начнем с разрешений (permissions). Если открыть админ-панель сайта, то в разделе пользователей:

http://127.0.0.1:8000/admin/users/user/

при их редактировании в самом низу видим возможность назначения групп и разрешений. Причем список стандартных разрешений для разных таблиц БД уже сформирован. Фреймворк Django делает это на автомате. Как только появляется новая таблица, то для нее создается минимум четыре разрешения:

  • add – на добавление новых записей;
  • change – на изменение существующих записей;
  • delete – на удаление записей;
  • view – на просмотр записей.

Давайте для примера пользователю с логином user1 добавим разрешение на добавление записи в таблицу women. Сейчас это действие никак не влияет на функционал нашего сайта. По-прежнему, добавлять статью может любой пользователь. Чтобы, например, ограничить доступ к странице:

http://127.0.0.1:8000/addpage/

и отображать ее только пользователям с разрешением на добавление новой записи в таблицу women, в классе представления AddPage следует прописать базовый класс миксина PermissionRequiredMixin, а само разрешение указать с помощью атрибута permission_required следующим образом:

permission_required = 'women.add_women'

Обратите внимание на имя стандартного разрешения. Сначала пишется имя приложения, в котором срабатывает представление AddPage, затем, через точку название самого разрешения add и через подчеркивание – имя таблицы women. Так определяются имена всех стандартных разрешений:

<приложение>.<действие>_<таблица>

Сейчас пользователь user1 получает доступ к странице «Добавить статью». Давайте теперь попробуем зайти на эту страницу пользователем user2, который не имеет этого разрешения. Видим код ошибки 403 – доступ запрещен. Но, обратите внимание, суперпользователь по умолчанию имеет все права, поэтому он также может зайти на эту страницу.

Давайте еще ограничим доступ к странице редактирования постов. За это отвечает представление UpdatePage. Также унаследуем его от класса миксина PermissionRequiredMixin и пропишем атрибут:

permission_required = 'women.change_women'

Теперь ни один из пользователей (кроме суперпользователя) не может получить доступ к этой странице:

http://127.0.0.1:8000/edit/shakira/

Давайте пользователю user2 дадим право менять и удалять записи. Видим, что он теперь получает доступ к странице редактирования.

Если же мы хотим назначить разрешение функции представления, то это делается с помощью специального декоратора permission_required:

@permission_required(perm='women.view_women', raise_exception=True)
def contact(request):
    return HttpResponse("Обратная связь")

Здесь второй параметр raise_exception нужен для генерации кода 403 – доступ запрещен. Иначе, мы будем перенаправлены на страницу авторизации, что было бы странно для авторизованного пользователя.

Вот пример того, как можно отдельным пользователям назначать разрешения и ограничивать доступ к страницам сайта на их основе.

Использование разрешений в шаблонах

Следующим шагом посмотрим, как можно использовать разрешения внутри шаблонов. Предположим, мы бы хотели выводить ссылку «Редактировать» при просмотре статей, но только тем пользователям, которые имеют право менять существующие записи в таблице women. Это разрешение вида:

women.change_women

Для этого в каждый шаблон фреймворк Django автоматически передает коллекцию perms, содержащую разрешения текущего пользователя (если он авторизован). Например, если в шаблоне women/post.html в блоке breadcrumbs записать:

{{ perms }}

то должны увидеть объект PermWrapper. Но мы вместо него запишем следующую конструкцию:

{% if perms.women.change_women %}
<p ><a href="{% url 'edit_page' post.slug %}">Редактировать</a></p>
{% endif %}

Здесь проверяется наличие разрешения women.change_women и, если оно есть у пользователя, то отображается ссылка «Редактировать». Если это разрешение отсутствует, то ссылка появляться не будет. Как видите, все делается очень просто.

Группы (Groups)

На практике не редко возникают ситуации, когда определенным пользователям нужно назначить один и тот же набор разрешений. Чтобы каждый раз не запоминать этот набор, его можно объединить в группу и, затем, пользователям назначать нужную группу (или несколько групп).

Группы можно создавать непосредственно в админ-панели:

http://127.0.0.1:8000/admin/

Например, создадим группу с именем moderator и поместим в нее все четыре разрешения для модели women. Затем, пользователю user1 присвоим эту группу и удалим все дополнительные разрешения. Теперь, при просмотре отдельных постов, ему будет показываться ссылка «Редактировать», так как он обладает всеми четырьмя разрешениями, прописанными в группе. Если пользователь будет состоять в нескольких группах, то все их разрешения объединяются.

Команды работы с разрешениями и группами

Иногда, при разработке проектов, нам приходится работать с группами и разрешениями на уровне следующих команд:

myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()
myuser.has_perm(permission)

Этот список взят из документации по адресу:

https://docs.djangoproject.com/en/4.2/topics/auth/default/#permissions-and-authorization

Здесь все достаточно очевидно. Откроем консоль фреймворка Django:

python manage.py shell

Импортируем модель User и прочитаем запись с id=2:

from users.models import User
user = User.objects.get(pk=2)

У этого пользователя есть внешние ключи groups и user_permissions:

user.groups
user.user_permissions

Соответственно, мы можем через них работать с группами и разрешениями. Например:

user.has_perm('women.add_women') # True
user.has_perm(women.delete_category') # False

Для добавления новых разрешений можно указывать или их id, например:

user.user_permissions.add(1)
user.user_permissions.all()

или объекты:

from django.contrib.auth.models import Permission
p = Permission.objects.get(codename='add_category')
user.user_permissions.add(p)

То же самое с группами:

from django.contrib.auth.models import Group
g = Group.objects.get(name='moderator')
user.groups.add(g)

или

user.groups.add(1)

То есть, все достаточно очевидно. Соответственно, мы можем удалять группы:

user.groups.remove(g)

или так:

user.groups.remove(1)

Очищать список групп:

user.groups.clear()

И то же самое с разрешениями:

user.user_permissions.remove(p)
user.user_permissions.remove(1)
user.user_permissions.clear()

Создание пользовательских разрешений

Иногда на практике возникает необходимость в создании собственных, дополнительных разрешений к списку уже существующих. В самом простом варианте это можно сделать через консоль Django следующим образом:

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
content_type = ContentType.objects.get_for_model(User)
permission = Permission.objects.create(codename="social_auth", name="Social Auth",  content_type=content_type)

Мы для модели User создали новое разрешение с кодовым именем social_auth, например, чтобы отмечать пользователей, авторизованных через социальные сети. На последующих занятиях мы с вами это будем делать.

Если теперь посмотреть на список разрешений в окне админ-панели редактирования пользователей, то увидим новый пункт с именем Social Auth для модели user приложения users. А как будет использоваться это разрешение, вы узнаете на последующих занятиях.

Курс по Django: https://stepik.org/a/183363

Видео по теме