Курс по Django: https://stepik.org/a/183363
После того, как
мы с вами познакомились с управлением доступа через классы permissions, пришло время
узнать, а как можно выполнять авторизацию и аутентификацию пользователей через API-запросы. Я
напомню, что авторизация – это когда пользователь входит в систему, обычно по
логину и паролю и сервер идентифицирует этого пользователя. А при обращении к
закрытым страницам этого сайта (например, личному кабинету) сервер выполняет
аутентификацию пользователя, то есть, проверяет, вошел пользователь в систему
или это обычный сторонний посетитель, которому не следует давать доступ. Таким
образом, процессы авторизации и аутентификации пользователей тесно связаны
между собой.
Django REST Framework поддерживает
несколько способов авторизации. Среди встроенных и поставляемых с самим пакетом
– это авторизация на основе сессий и токенов. Дополнительно в проектах нередко
используют авторизацию на основе токенов с помощью пакета Djoser, JWT (JSON Web Token) авторизацию,
ну и, конечно же, при необходимости авторизацию через социальные сети с
использованием пакета Django REST framework OAuth. Подробно обо всем этом можно
почитать на странице официальной документации:
https://www.django-rest-framework.org/api-guide/authentication/
Как видите,
способов авторизации и аутентификации множество, а сторонних пакетов, которые
их реализуют еще больше. Как во всем этом не потеряться? Для этого, очевидно,
нужно хорошо понимать принципы работы различных алгоритмов авторизации, знать
их сильные и слабые стороны, а, затем, при разработке конкретных проектов,
выбирать наиболее подходящие варианты.
Авторизация на основе сессий (session-based)
Исторически,
одним из первых способов авторизации и аутентификации пользователей основывается
на cookies браузеров и
сессиях сервера. Он широко используется и поныне. Идея алгоритма очень проста.
Чтобы клиент был успешно идентифицирован на стороне сервера, он прежде должен
войти в систему (полагаем, что он в ней уже зарегистрирован). Для этого сервер
отправляет в браузер форму для ввода логина и пароля (опять же, как пример). Пользователь
их вводит и отправляет POST-запрос с данными обратно на сервер.
Сервер ищет в БД пользователя с указанными логином и паролем. Если не находит,
то возвращает ошибку, например «Неверная пара логин/пароль». Если находит, то
формирует идентификатор сессии в виде набора произвольных букв и цифр:
d3N2OnBhc3N3b3JkMTIz
заносит это
значение в таблицу сессий, связывая session_id с пользователем
(user_id). Затем, session id отправляется
клиенту и браузер сохраняет его в своих cookies. Это процедура
авторизации посредством сессий и cookies.
Если
пользователь авторизован и в браузере хранится id сессии, то он
может получать доступ к определенным, закрытым страницам сайта. Для этого,
например, при GET-запросе, в
заголовке прописывается строчка:
Authorization:
Basic d3N2OnBhc3N3b3JkMTIz
в которой передается session id. Сервер ищет принятый id сессии с
записями в БД и если находит такой session_id, то
идентифицирует пользователя и разрешает ему доступ к закрытым страницам. Если
же, по каким-либо причинам session_id в БД не
находится, то авторизация не проходит и доступ остается закрытым.
Как правило,
идентификатор сессии существует ограниченное время: от нескольких минут до
нескольких месяцев. Реже – постоянно. Также session id меняется, если
пользователь выйдет из системы. В этом случае запись удаляется из таблицы и
повторная попытка зайти под этим же идентификатором уже будет безуспешной.
Пользователю нужно будет снова войти в систему, будет назначен другой session id и доступ вновь
будет открыт.
Вот так, в
целом, работает авторизация и аутентификация пользователей на основе сессий и cookies. Недостатком
этого подхода является то, что пользователь оказывается жестко привязанным к
устройству (браузеру), в котором в cookies хранится id сессии. Попытка
зайти на сайт с другого устройства (если там нет актуальной записи в cookies) будет
безуспешной. Нужно будет заново вводить логин и пароль. Также сложно
поддерживать такую авторизацию для сайтов, использующих несколько доменных
имен, так как cookies привязывается к
определенному домену.
Реализация session-based аутентификации в DRF
Несмотря на эти
недостатки, авторизация и аутентификация этим способом довольно распространена
и встроена в Django REST Framework. Реализуется
она очень просто. Достаточно в коллекции urlpatterns (в файле drfsite/urls.py) прописать
строчку:
urlpatterns = [
...
path('api/v1/drf-auth/', include('rest_framework.urls'))
]
Все. Запускаем
тестовый веб-сервер, переходим по адресу:
http://127.0.0.1:8000/api/v1/drf-auth/
и нам здесь
отображаются поддерживаемые маршруты, в частности:
-
api/v1/drf-auth/login/ - для входа в
систему;
-
api/v1/drf-auth/logout/ - для выхода
из системы.
Мало того, если
выполнить любой API-запрос для DRF, например:
http://127.0.0.1:8000/api/v1/women/
то вверху на
панели увидим ссылку для авторизации. Нажмем на нее, появится окно для ввода
логина и пароля:
Мы можем войти
здесь под администратором, так как DRF полностью интегрирован с
фреймворком Django и все
зарегистрированные на сайте пользователи автоматически могут использовать
систему авторизации и аутентификации DRF.
После входа
возвращаемся на прежнюю страницу и видим, что мы были успешно авторизованы и
идентифицированы системой, так как внизу списка появилась форма для добавления
новой записи. А мы помним, что на предыдущем занятии сделали так, чтобы эта
форма появлялась только для авторизованных пользователей.
Чтобы убедиться,
что аутентификация пользователя производится по session id, можно открыть
в браузере панель «Инспектор», перейти во вкладку «Network», обновить
страницу и здесь (в самом верху выбрать страницу) можно посмотреть на
содержимое переданного заголовка. В частности, мы видим следующую строчку для cookie:
csrftoken=CBwenFKcZc9uHFFqVDqWRyxJZYhUxBXinHFOUk4B2aOCC0I2HByf3KlUhy5WwTwv;
sessionid=oyg9fmyh6t8g3wsk73ut4ayiagzid2a1
Здесь,
во-первых, имеется csrftoken для защиты от взлома (подмены устройства, с
которого осуществляется вход) и, во-вторых, sessionid, по которому выполняется
аутентификация пользователя. То есть, при каждом запросе от клиента должна
поступать эта информация, чтобы сервер мог корректно идентифицировать
пользователя и разрешить ему вход в систему.
Я постарался
предельно просто и доступно изложить идею авторизации на основе сессий и cookies, а также
продемонстрировал, как можно подключить этот тип аутентификации пользователей в
Django REST Framework. На следующем
занятии мы продолжим эту тему и поговорим о более распространенном способе аутентификации
для API-запросов через
токены.
Курс по Django: https://stepik.org/a/183363