Улучшение процесса авторизации (Flask-Login)

Файл проекта: https://github.com/selfedu-rus/flasksite-16

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

@app.route('/profile')
@login_required
def profile():
    return f"""<a href="{url_for('logout')}">Выйти из профиля</a>
                user info: {current_user.get_id()}"""

Мы здесь используем специальную своего рода глобальную переменную current_user (для простоты ее можно так воспринимать), через которую можно обращаться к методам класса UserLogin. В частности, используется метод get_id для получения идентификатора авторизованного пользователя. И также добавлена ссылка для выхода из профиля. Чтобы она заработала, необходимо прописать функцию представления logout:

@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash("Вы вышли из аккаунта", "success")
    return redirect(url_for('login'))

В этой функции мы вызываем специальный метод logout_user(), который очищает сессию и делает пользователя не авторизованным. Затем, формируется мгновенное сообщение и перенаправление на форму авторизации.

Далее, реализуем возможность оставаться в системе после закрытия окна браузера. Для этого нужно прочитать данные для checkbox’a «Запомнить меня»:

rm = True if request.form.get('remainme') else False

и при вызове функции login_user передать это значение параметру remember:

login_user(userlogin, remember=rm)

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

Следующий шаг улучшения

Предположим, что мы не авторизованы и пытаемся посетить закрытую страницу. В этом случае сервер возвратит код 401 – страница недоступна. Но это не лучшее поведение сайта. Более дружественный интерфейс должен перенаправлять пользователя, например, на форму авторизации. Это делается следующей строчкой:

login_manager.login_view = 'login'

то есть, мы здесь атрибуту login_view присваиваем имя функции представления для формы авторизации. И, далее, пропишем еще две такие строки:

login_manager.login_message = "Авторизуйтесь для доступа к закрытым страницам"
login_manager.login_message_category = "success"

Они будут формировать мгновенное сообщение для таких ситуаций.

Наконец, последний важный штрих. Если авторизованный пользователь перейдет по адресу /login, то он увидит форму авторизации, что как-то неестественно – он же уже вошел на сайт! Поэтому в обработчике login в самом начале можно сделать такую проверку:

    if current_user.is_authenticated:
        return redirect(url_for('profile'))

Снова обращаемся к глобальному объекту current_user и проверяем: является ли пользователь авторизованным. Если это так, то делаем автоматическое перенаправление на страницу профайла.

Но, что если неавторизованный пользователь попытается просмотреть материал статьи? Тогда мы тоже попадем на страницу авторизации, но после этого произойдет перенаправление в профайл. Но лучше делать перенаправление на исходную страницу – со статьей. Сделаем это.

Смотрите, когда происходит перенаправление, Flask в строке запроса автоматически добавляет специальный параметр next, который ссылается на предыдущую страницу, с которой ушли. Воспользуемся им и в шаблоне login.html пропишем вот такие строчки:

<form action="" method="post" class="form-contact">

Здесь происходит дублирование обратного URL-адреса, который был в браузере. Далее, в обработчике /login сделаем перенаправление с учетом наличия этого параметра:

return redirect(request.args.get("next") or url_for("profile"))

Мы перейдем либо на предыдущую страницу, либо в профайл, если параметр next отсутствует. Все, вот таким образом, в самом простом варианте мы реализовали авторизацию пользователя на нашем сайте. Но, несмотря на эту простоту, здесь продемонстрированы основные подходы и возможности модуля Flask-Login. И теперь вы сможете использовать его на своих сайтах.

Самый последний штрих – UserMixin

И последний, момент, который я все-таки решил вставить в это занятие – это вспомогательный класс UserMixin, который по умолчанию реализует методы: is_authenticated, is_active, is_anonymous и, потому, наш класс UserLogin можно записать в несколько более кратком виде:

from flask_login import UserMixin
 
class UserLogin(UserMixin):
    def fromDB(self, user_id, db):
        self.__user = db.getUser(user_id)
        return self
 
    def create(self, user):
        self.__user = user
        return self
 
    def get_id(self):
        return str(self.__user['id'])

При этом весь функционал сохраняется без изменений.

Разумеется, учесть и рассказать обо всех нюансах авторизации с помощью модуля Flask-Login в видеоуроках просто нереально. Я привел общий принцип пользования этим пакетом. Дополнительную информацию можно посмотреть на сайте официальной документации:

https://flask-login.readthedocs.io/en/latest/

Видео по теме