[old] Авторизация пользователя - moevm/mse_teacher_plan GitHub Wiki

Объект пользователя

Объекты User - основа системы аутентификации. Они представляют пользователей сайта и используются для проверки прав доступа, регистрации пользователей, ассоциации данных с пользователями. Для представления пользователей в системе аутентификации используется только один класс, таким образом 'суперпользователи' или 'персонал' - это такие же объекты пользователей, просто с определёнными атрибутами.

Основные атрибуты пользователя:

  • username
  • password
  • email
  • first_name
  • last_name

Создание пользователей:

Самый простой способ создать пользователя – использовать метод create_user():

from django.contrib.auth.models import User

user = User.objects.create_user('john', '[email protected]', 'johnpassword')

user.last_name = 'Lennon'

user.save()

Создание суперпользователя

Суперпользователя можно создать с помощью команды createsuperuser:

$ python manage.py createsuperuser --username=joe [email protected]

Команда попросит ввести пароль. Пользователь будет создан сразу же по завершению команды. Если не указывать --username или --email, команда попросит ввести их.

Смена пароля

Django не хранит пароль в открытом виде, хранится только хеш. Именно по этой причине пользователь создается через специальную функцию.

Пароль можно сменить несколькими способами:

Команда manage.py changepassword *username* позволяет сменить пароль пользователя через консоль. Команда требует ввести пароль дважды. Если введённые значения совпадают, то пароль будет изменен. Если не указать имя пользователя, команда попробует найти пользователя с именем текущего системного пользователя.

Вы можете изменить пароль программно, используя метод set_password():

from django.contrib.auth.models import User

u = User.objects.get(username='john')

u.set_password('new password')

u.save()

Аутентификация пользователей

Для аутентификации пользователя по имени и паролю используйте authenticate(). Параметры авторизации передаются как именованные аргументы, по умолчанию это username и password, если пароль и имя пользователя верны, будет возвращен объект User. Если пароль не правильный, authenticate() возвращает None. Например:

from django.contrib.auth import authenticate

user = authenticate(username='john', password='secret')

if user is not None:

if user.is_active:

print("User is valid, active and authenticated")

else

print("The password is valid, but the account has been disabled!")

else

print("The username and password were incorrect.")

Права доступа и авторизация

Django предоставляет простую систему проверки прав. Она позволяет добавлять права пользователю или группе пользователей.

Эта система используется админкой Django, но вы можете использовать её и в своем коде.

Админка использует проверку прав следующим образом:

  • При доступе к странице добавления объекта проверяется наличие права “add” для объектов этого типа.

  • При доступе к страницам просмотра списка объектов и изменения объекта проверяется наличие права “change” для объектов этого типа.

  • При удалении объекта проверяется наличие права “delete” для объектов этого типа.

Права доступа можно добавлять не только типу объекта, но и конкретному объекту. Переопределив методы has_add_permission(), has_change_permission() и has_delete_permission() класса ModelAdmin, можно проверять права для конкретного объекта.

Модель User содержит связи многое ко многим с таблицами groups и user_permissions. Объект модели User работает со связанными моделями, как и другие модели Django:

myuser.groups = [group_list]

myuser.groups.add(group, group, ...)

myuser.groups.remove(group, group, ...)

myuser.groups.clear()

myuser.user_permissions = [permission_list]

myuser.user_permissions.add(permission, permission, ...)

myuser.user_permissions.remove(permission, permission, ...)

myuser.user_permissions.clear()

Права доступа по умолчанию

Если добавить приложение django.contrib.auth в параметр конфигурации INSTALLED_APPS, оно добавит права доступа по умолчанию – “add”, “change” и “delete” – для каждой модели из установленных приложений.

Эти права доступа создаются при выполнении команды manage.py migrate. При первом выполнении migrate, после добавления django.contrib.auth в INSTALLED_APPS, права доступа по умолчанию создаются для всех старых и новых моделей. Для каждой новой модели они добавляются при выполнении manage.py migrate.

Предположим у вас есть приложение с app_label foo и модель Bar. Чтобы проверить права доступа, используйте:

  • add: user.has_perm('foo.add_bar')
  • change: user.has_perm('foo.change_bar')
  • delete: user.has_perm('foo.delete_bar')

Модель Permission редко используется напрямую.

Группы

Модель django.contrib.auth.models.Group предоставляет возможность группировать пользователей, добавляя им набор прав доступа. Пользователь может принадлежать нескольким группам.

Пользователь, добавленный в группу, автоматически получает все права доступа этой группы. Например, если группа Site editors содержит права доступа can_edit_home_page, любой пользователь в этой группе получить это право доступа.

Также группы позволяют группировать пользователей, добавляя метки или дополнительные возможности. Например, вы можете создать группу 'Special users', и написать код, который предоставляет доступ к дополнительному функционалу сайта, или отправлять сообщения только пользователям этой группы.

Программное создание прав доступа

Кроме добавления своих прав доступа через класс Meta модели, вы также можете создать их напрямую. Например, создадим право доступа can_publish для модели BlogPost в приложении myapp.

from myapp.models import BlogPost

from django.contrib.auth.models import Group, Permission

from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(BlogPost)

permission = Permission.objects.create(codename='can_publish', name='Can Publish Posts', content_type=content_type)

Теперь его можно добавить объекту User через атрибут user_permissions или к объекту Group через атрибут permissions.

Кеширование прав доступа

ModelBackend кэширует права доступа объекта User после первого запроса на их получение. Такой подход удобен для цикла запрос-ответ, т.к. права доступа редко проверяются сразу же после их изменения (например, в админке). Если вы изменяете и проверяете права доступа в одном запросе или в тестах, проще всего заново загрузить объект User из базы данных. Например:

from django.contrib.auth.models import Permission, User

from django.shortcuts import get_object_or_404

def user_gains_perms(request, user_id):

user = get_object_or_404(User, pk=user_id)

any permission check will cache the current set of permissions

user.has_perm('myapp.change_bar')

permission = Permission.objects.get(codename='change_bar')

user.user_permissions.add(permission)

Checking the cached permission set

user.has_perm('myapp.change_bar') False

Request new instance of User

user = get_object_or_404(User, pk=user_id)

Permission cache is repopulated from the database

user.has_perm('myapp.change_bar') True

Аутентификация в запросах

Django использует сессию и промежуточный слой для работы системы аутентификации в объекте запроса.

Этот механизм предоставляет атрибут request.user для каждого запроса, который возвращает текущего пользователя. Если текущий пользователь не авторизован, атрибут содержит экземпляр AnonymousUser, иначе экземпляр User.

Различить их можно с помощью метода is_authenticated():

if request.user.is_authenticated():

...

else:

...

Как авторизовать пользователя

Если вы ходите привязать к сессии авторизованного пользователя, используйте функцию login().

login()

Чтобы авторизовать пользователя в представлении, используйте функцию login(). Она принимает объект HttpRequest и объект User. Функция login() сохраняет идентификатор пользователя в сессии, используя Django приложение для работы с сессиями.

Следует отметить, что любые данные установленные в анонимной сессии будут сохранены в сессии пользователя после его авторизации.

Данный пример показывает как вы можете использовать обе функции authenticate() и login():

from django.contrib.auth import authenticate, login

def my_view(request):

username = request.POST['username']

password = request.POST['password']

user = authenticate(username=username, password=password)

if user is not None:

if user.is_active:

login(request, user)

Redirect to a success page.

else:

Return a 'disabled account' error message

...

else:

Return an 'invalid login' error message.

...

Как отменить авторизацию пользователя

logout()

Для отмены авторизации пользователя, который был авторизован с помощью функции django.contrib.auth.login(), следует использовать функцию django.contrib.auth.logout() в коде вашего представления. Функция принимает объект HttpRequest и не возвращает никаких значений. Например:

from django.contrib.auth import logout

def logout_view(request):

logout(request)

Следует отметить, что функция logout() не выбрасывает никаких ошибок, если пользователь не был ранее авторизован.

При вызове функции logout() в рамках текущего запроса будут очищены все данные сессии. Все существующие данные будут стёрты. Это происходит для того, чтобы предотвратить возможность доступа к этим данным для другого пользователя, который будет использовать тот же браузер для своей авторизации. Если потребуется поместить некие данные в сессию, которые должны быть доступны пользователя сразу после отмены его авторизации, выполняйте это после вызова функции django.contrib.auth.logout().

Ограничение доступа для неавторизованных пользователей

Прямой путь

Самым простым способом ограничить доступ к страницам является использование метода request.user.is_authenticated() и, при необходимости, перенаправление на страницу авторизации:

from django.conf import settings

from django.shortcuts import redirect

def my_view(request):

if not request.user.is_authenticated():

return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

...

или отображение в виде ошибки

from django.shortcuts import render

def my_view(request):

if not request.user.is_authenticated():

return render(request, 'myapp/login_error.html')

...

Декоратор login_required

login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None]) Для краткости кода вы можете использовать декоратор login_required():

from django.contrib.auth.decorators import login_required

@login_required

def my_view(request):

...

Функция login_required() делает следующее:

  • Если пользователь не авторизован, то перенаправляет его на URL, указанный в параметре конфигурации settings.LOGIN_URL, передавая текущий абсолютный путь в запросе. Например: /accounts/login/?next=/polls/3/.

  • Если пользователь авторизован, то выполняет код представления. В коде представления не требуется выполнять проверку авторизован ли пользователь или нет.