Сообщить об ошибке.

Расширение Flask-Login, управление сеансами пользователей

Расширение Flask-Login обеспечивает управление сеансами пользователей для Flask. Расширение выполняет общие задачи входа в систему, выхода из системы и запоминания сеансов пользователей в течение длительных периодов времени.

Что умеет расширение Flask-Login:

  • Сохраняет идентификатор активного пользователя в сеансе Flask и позволяет легко входить и выходить из него.
  • Позволяет ограничить просмотр защищенных URL-адресов только вошедшим в систему пользователям.
  • Выполняет функцию "запомнить меня".
  • Помогает защитить сеансы пользователей от кражи файлов cookie.

Расширение Flask-Login не ограничивает разработчика:

  • использованием определенной базы данных или метода хранения пользователей. Вы полностью отвечаете за то, как загружается пользователь.
  • использованием имен пользователей и паролей, OpenID или любого другого метода аутентификации.
  • не обрабатывает регистрацию пользователей или восстановления учетной записи.
  • не обрабатывает разрешения пользователей (например, роли) помимо "вошел в систему или нет".

Содержание:


Установка модуля Flask-Login в виртуальное окружение.

Так как модуль Flask-Login не входит в стандартную библиотеку Python, его необходимо установить отдельно. Cделать это можно с помощью менеджера пакетов pip.

# создаем виртуальное окружение, если нет
$ python3 -m venv .venv --prompt VirtualEnv
# активируем виртуальное окружение 
$ source .venv/bin/activate
# обновляем `pip`
(VirtualEnv):~$ python3 -m pip install -U pip
# ставим модуль `Flask-Login`
(VirtualEnv):~$ python3 -m pip install -U flask-login

Настройка приложения Flask

Наиболее важной частью приложения, использующего расширение Flask-Login, является класс менеджера входа LoginManager. Для приложения Flask, класс LoginManager создается в файле (обычно) __init__.py. Менеджер входа содержит код, который позволяет приложению и расширению Flask-Login работать вместе, например, как загружать пользователя по идентификатору, куда отправлять пользователей, когда им необходимо войти в систему, и тому подобное.

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

from flask import Flask
from flask_login import LoginManager

app = Flask(__name__)
# ВАЖНО! Обязательно установите для `SECRET_KEY` что-то сложное
app.config['SECRET_KEY'] = 'Top ... secret!'
# создаем объект менеджера и добавляем его в приложение
login_manager = LoginManager(app)

По умолчанию Flask-Login использует сеансы для аутентификации. Это означает, что необходимо установить секретный ключ в приложении, иначе Flask выдаст сообщение об ошибке. Дополнительно смотрите документацию по flask.session.

ВАЖНО! ОБЯЗАТЕЛЬНО используйте команду для генерации сложного/хорошего секретного ключа. НЕ используйте пример.

Как взаимодействует Flask-Login с приложением Flask

Необходимо предоставить/написать функцию обратного вызова, например user_loader() и украсить ее декоратором @login_manager.user_loader. Этот обратный вызов используется для перезагрузки объекта пользователя из идентификатора пользователя, хранящегося в сеансе. Он должен принять ID пользователя в виде строки str и вернуть соответствующий объект пользователя. Например:

@login_manager.user_loader
def user_loader(user_id):
    return User.get(user_id)

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

Класс пользователя User.

Класс User, который используется для представления пользователей, должен реализовать следующие свойства и методы:

  • User.is_authenticated - Это свойство должно возвращать значение True, если пользователь прошел проверку подлинности, т. е. предоставил действительные учетные данные. (Только прошедшие проверку подлинности пользователи будут соответствовать критериям login_required.)

  • User.is_active - Это свойство должно возвращать значение True, если это активный пользователь - помимо проверки подлинности он также активировал свою учетную запись, не был приостановлен или не имеет каких-либо условий, предусмотренных приложением для отклонения учетной записи. Неактивные учетные записи не могут войти в систему (конечно, без принудительного вмешательства).

  • User.is_anonymous - Это свойство должно возвращать значение True, если это анонимный пользователь. (Фактические пользователи (НЕ анонимные) должны вместо этого возвращать False)

  • User.get_id() - Этот метод должен возвращать строку, которая однозначно идентифицирует этого пользователя и может использоваться для загрузки пользователя из обратного вызова user_loader(user_id). Обратите внимание, что это должна быть строка - если идентификатор изначально имеет тип int или какой-либо другой тип, то нужно будет преобразовать его в str.

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

Упрощенный пример взаимодействия (для понимания)

Например, для простоты напишем базовый класс User, а в качестве "базы данных пользователей" будем использовать словарь. В реальном приложении это будет реальный уровень персистентности. Важно отметить, что это особенность Flask-Login - не важно, как хранятся данные, необходимо указать, как их получить!

# псевдокод для понимания происходящего

from flask_login import UserMixin

# словарь пользователей в качестве БД
users = {"user_login": User("user_login")}

# базовый класс пользователя, который  
# наследуется от `UserMixin`
class User(UserMixin):
    def __init__(self, email):
        # в качестве ID пользователя используем `email`
        self.id = email

# Сообщаем менеджеру входа, как загружать пользователя
# Если ни один пользователь не найден, возвращается `None`.
@login_manager.user_loader
def user_loader(id):
    # получаем объект пользователя `User()`
    # из словаря `users` методом словаря `.get()`
    return users.get(id, None)

Далее функция-представление login() заполнит сеанс с информацией для аутентификации (при успешном входе) и перенаправит на функцию-представление protected(), которое будет доступно только аутентифицированным пользователям, в противном случае покажет ошибку. Функция-представление logout() очищающее сеанс.

# псевдокод для понимания происходящего

@app.get("/login")
# Запрос GET предоставляет форму  
# ввода Email и Password
def login():
    return """<form method=post>
      Email: <input name="email"><br>
      Password: <input name="password" type=password><br>
      <button>Log In</button>
    </form>"""

@app.post("/login")
# Запрос POST обрабатывает введенные  
# Email и Password
def login_post():
    # получаем `email`
    user = users.get(flask.request.form["email"])

    # проверяем поступившие данные на валидность
    if user is None or user.password != flask.request.form["password"]:
        # если данные НЕ ВАЛИДНЫ, то перенаправляем 
        # пользователя обратно на форму авторизации
        return flask.redirect(flask.url_for("login"))

    # регистрируем сессию(сеанс) пользователя   
    flask_login.login_user(user)
    # перенаправляем на защищенную страницу
    return flask.redirect(flask.url_for("protected"))

@app.route("/protected")
# проверка сеанса (сессии) пользователя
@flask_login.login_required
def protected():
    return flask.render_template_string(
        "Logged in as: {{ user.id }}",
        user=flask_login.current_user
    )

@app.route("/logout")
def logout():
    # удаление сеанса пользователя
    flask_login.logout_user()
    return "Logged out"

Flask-Login например, может работать с пользовательскими моделями, основанными на любой системе баз данных. В этом случае класс User может интегрироваться в модель БД:

from flask_login import UserMixin
...

class User(UserMixin, db.Model):
    ...

Функция-представление login() в реальном приложении

В примере используется класс LoginForm расширения Flask WTForms для функции-представления и проверки данных формы на стороне клиента.

from flask_login import current_user, login_user
from werkzeug.security import generate_password_hash, check_password_hash

...

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('protected'))

    # Используется класс `LoginForm` для проверки 
    # данных формы на стороне клиента
    form = LoginForm()

    if form.validate_on_submit():
        # получаем данные из формы 
        email = form.email.data
        password = form.password.data
        # получаем данные пользователя из БД по `email`
        user = User.query.filter_by(email).first()
        # проводим валидацию полученных данных
        if user and werkzeug.security.check_password_hash(user.password_hash, password):
            # регистрируем сеанс пользователя 
            # здесь `user` должен быть экземпляром класса `User`
            user = User(email, remember=form.remember_me.data)
            login_user(user)

            flask.flash('Вы успешно вошли в систему.')

            next = flask.request.args.get('next')
            # Здесь функция `url_has_allowed_host_and_scheme()` должна проверить, 
            # безопасен ли URL-адрес для перенаправления, т.е. что он соответствует.
            #  хосту запроса. Смотрите пример `url_has_allowed_host_and_scheme()` для Django.
            if not url_has_allowed_host_and_scheme(next, request.host):
                return abort(400)

        return redirect(next or url_for('protected'))
    return render_template('login.html', form=form)

ВАЖНО. Для безопасности НЕОБХОДИМО проверить значение параметра next. Если этого не сделать, то приложение будет уязвимо для открытых перенаправлений. Пример реализации url_has_allowed_host_and_scheme можно подсмотреть в исходных кодах Django.

Затем можно получить доступ к вошедшему в систему пользователю с помощью прокси current_user, который доступен в каждом шаблоне:

{% if current_user.is_authenticated %}
  Hi {{ current_user.name }}!
{% endif %}

Функция-представление, требующая от пользователей входа в систему, может быть украшена декоратором @login_required:

@app.route("/settings")
@login_required
def settings():
    pass

Когда пользователь готов выйти из системы:

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(somewhere)

Пользователи будут отключены, а все файлы cookie, относящиеся к их сеансу, будут удалены.

Настройка процесса входа в систему

По умолчанию, когда пользователь пытается получить доступ к защищенному URL-адресу с декоратором @login_required без входа в систему, Flask-Login отображает сообщение и перенаправляет его в представление login(). (Если представление с именем login не определено, то будет прервано с ошибкой 401.)

Имя функции-представления входа в систему можно установить как LoginManager.login_view. Это также может быть абсолютный URL-адрес, если механизм аутентификации является внешним по отношению к приложению. Например:

login_manager.login_view = "log_in"

По умолчанию высвечивается сообщение: Please log in to access this page. Чтобы настроить сообщение, необходимо переопределить LoginManager.login_message:

login_manager.login_message = ('Пожалуйста, войдите в систему, '
                               'чтобы получить доступ к этой странице')

Чтобы настроить категорию сообщений, необходимо установить LoginManager.login_message_category:

login_manager.login_message_category = "info"

Когда представление login() перенаправляет пользователя на защищенную страницу, то в строке запроса будет переменная next, которая представляет собой страницу, к которой пользователь пытался получить доступ. Альтернативно, если ключ конфигурации USE_SESSION_FOR_NEXT имеет значение True, то страница сохраняется в сеансе под ключом next.

Если необходимо дополнительно настроить процесс входа в систему, то можно украсить функцию LoginManager.unauthorized_handler:

@login_manager.unauthorized_handler
def unauthorized():
    # do stuff
    return a_response

Например: Flask-Login используется с Flask-Restful. В API (проект с именем api) не нужно делать перенаправление на страницу входа, а возвращать код несанкционированного состояния:

from flask import redirect, url_for, request
from http import HTTPStatus
@login_manager.unauthorized_handler
def unauthorized():
    if request.blueprint == 'api':
        abort(HTTPStatus.UNAUTHORIZED)
    return redirect(url_for('site.login'))

Пользовательский вход в систему с помощью загрузчика запросов

Например иногда нужно осуществлять вход пользователей без использования файлов cookie, используя значения заголовков или ключ API, передаваемый в качестве аргумента запроса. В этих случаях следует использовать обратный вызов LoginManager.request_loader. Этот обратный вызов должен вести себя так же, как обратный вызов LoginManager.user_loader, за исключением того, что он принимает запрос Flask вместо user_id.

Например, чтобы поддерживать вход как с помощью аргумента URL, так и с помощью базовой аутентификации с использованием заголовка авторизации:

@login_manager.request_loader
def load_user_from_request(request):

    # сначала пробуем войти, используя api_key
    api_key = request.args.get('api_key')
    if api_key:
        user = User.query.filter_by(api_key=api_key).first()
        if user:
            return user

    # затем пробуем войти, используя базовую аутентификацию.
    api_key = request.headers.get('Authorization')
    if api_key:
        api_key = api_key.replace('Basic ', '', 1)
        try:
            api_key = base64.b64decode(api_key)
        except TypeError:
            pass
        user = User.query.filter_by(api_key=api_key).first()
        if user:
            return user

    # возвращаем `None`, если оба метода 
    # не выполнили вход пользователя.
    return None

Анонимные пользователи

По умолчанию, когда пользователь фактически не вошел в систему, для параметра current_user устанавливается объект AnonymousUserMixin.

Он имеет следующие свойства и методы:

  • AnonymousUserMixin.is_active = False;
  • AnonymousUserMixin.is_authenticated = False;
  • AnonymousUserMixin.is_anonymous = True;
  • AnonymousUserMixin.get_id() возвращает None.

Если у есть особые требования к анонимным пользователям (например, у них должно быть поле role), то можно предоставить вызываемый объект (класс или фабричную функцию), которая создает анонимных пользователей в flask_login.LoginManager с помощью:

login_manager.anonymous_user = MyAnonymousUser

Функция "Запомнить меня"

По умолчанию, когда пользователь закрывает свой браузер, сеанс Flask удаляется, и пользователь выходит из системы. Функция "Запомнить меня" предотвращает случайный выход пользователя из системы при закрытии браузера. Это НЕ означает запоминание или предварительное заполнение имени пользователя или пароля пользователя в форме входа после выхода пользователя из системы.

Активация функции "Запомнить меня" происходит путем передачи аргумента remember=True вызову flask_login.login_user(). Файл cookie будет сохранен на компьютере пользователя, а затем Flask-Login автоматически восстановит идентификатор пользователя из этого файла cookie, если его нет в сеансе. Время до истечения срока действия файла cookie можно установить с помощью конфигурации REMEMBER_COOKIE_DURATION или передать его пользователю flask_login.login_user(). Файл cookie защищен от несанкционированного доступа, поэтому, если пользователь вносит в него изменения (т. е. вставляет чужой идентификатор пользователя вместо своего), файл cookie будет просто отклонен, как если бы его там не было.

Этот уровень функциональности обрабатывается автоматически. Если приложение обрабатывает какие-либо конфиденциальные данные то дополнительно необходимо предоставить дополнительную инфраструктуру для повышения безопасности файлов cookie.

Новые логины пользователей

Когда пользователь входит в систему, его сеанс помечается как "свежий", что указывает на то, что он действительно прошел аутентификацию в этом сеансе. Когда сеанс уничтожается и пользователь снова входят в систему с помощью файла cookie ("запомнить меня"), он помечается как "несвежий". Функция-декоратор flask_login.login_required не различает актуальность, что подходит для большинства страниц. При этом конфиденциальные действия, такие как изменение личной информации, должны требовать нового входа в систему. (Такие действия, как смена пароля, всегда должны требовать повторного ввода пароля)

Декоратор flask_login.fresh_login_required(), помимо проверки того, что пользователь вошел в систему, также гарантирует, что его логин свежий. В противном случае декоратор @fresh_login_required отправит пользователя на страницу, где он сможет повторно ввести свои учетные данные. Можно настроить его поведение так же, как и @login_required, установив LoginManager.refresh_view, LoginManager.needs_refresh_message и LoginManager.needs_refresh_message_category:

login_manager.refresh_view = "accounts.reauthenticate"
login_manager.needs_refresh_message = (
    u"To protect your account, please reauthenticate to access this page."
)
login_manager.needs_refresh_message_category = "info"

Или предоставив собственный обратный вызов для обработки обновления:

@login_manager.needs_refresh_handler
def refresh():
    # делаем что-то...
    return a_response

Чтобы снова пометить сеанс как свежий, нужно вызвать функцию flask_login.confirm_login().

Ключи конфигурации Flask-Login

  • COOKIE_NAME = "remember_token" - Имя файла cookie "Запомнить меня" по умолчанию
  • COOKIE_DURATION = timedelta(days=365) - Время по умолчанию до истечения срока действия файла cookie "Запомнить меня" (365 дней).
  • COOKIE_SECURE = False - Требуется ли для использования файла cookie "помни меня" защита
  • COOKIE_HTTPONLY = True - Независимо от того, использует ли файл cookie "Запомнить меня" только HttpOnly или нет
  • COOKIE_SAMESITE = None - Требуется ли для файла cookie "Запомнить меня" такое же происхождение
  • LOGIN_MESSAGE = "Please log in to access this page." - Флэш-сообщение по умолчанию, которое отображается, когда пользователям необходимо войти в систему.
  • LOGIN_MESSAGE_CATEGORY = "message" - Категория флэш-сообщений по умолчанию, отображаемая при входе пользователей в систему.
  • REFRESH_MESSAGE = "Please reauthenticate to access this page." - Флэш-сообщение по умолчанию, отображаемое при повторной аутентификации пользователей
  • REFRESH_MESSAGE_CATEGORY = "message" - Категория флэш-сообщений по умолчанию, отображаемая при повторной аутентификации пользователей
  • ID_ATTRIBUTE = "get_id" - Атрибут по умолчанию для получения идентификатора строки пользователя.
  • EXEMPT_METHODS = {"OPTIONS"} - Набор HTTP-методов, которые освобождены от flask_login.login_required и flask_login.fresh_login_required
  • USE_SESSION_FOR_NEXT = False - Если значение равно True, то страница, к которой пользователь пытается получить доступ, сохраняется в сеансе, а не в параметре URL при перенаправлении в режим входа в систему.
  • Набор сеансовых ключей, заполняемых Flask-Login, можно использовать для ручной безопасной и аккуратной очистки ключей.

    SESSION_KEYS = {
      "_user_id",
      "_remember",
      "_remember_seconds",
      "_id",
      "_fresh",
      "next",
    }
    

Настройки файлов cookie

  • REMEMBER_COOKIE_NAME = 'remember_token' - Название файла cookie, в котором хранится информация "Запомнить меня".
  • REMEMBER_COOKIE_DURATION = datetime.timedelta(days=365) - Количество времени до истечения срока действия файла cookie в виде объекта datetime.timedelta или целого числа секунд.
  • REMEMBER_COOKIE_DOMAIN = None - Если файл cookie "Запомнить меня" должен передаваться через домены, то здесь нужно установить значение домена (например, .example.com позволит использовать файл cookie на всех поддоменах example.com).
  • REMEMBER_COOKIE_PATH = '/' - Ограничивает доступ к файлу cookie "Запомнить меня" определенным путем.
  • REMEMBER_COOKIE_SECURE = False - Ограничивает область действия файла cookie "Запомнить меня" безопасными каналами (обычно HTTPS).
  • REMEMBER_COOKIE_HTTPONLY = True - Предотвращает доступ к файлу cookie "Запомнить меня" со стороны клиентских сценариев.
  • REMEMBER_COOKIE_REFRESH_EACH_REQUEST = False - Если установлено значение True, то файл cookie обновляется при каждом запросе, что увеличивает срок его действия. Работает как SESSION_REFRESH_EACH_REQUEST.
  • REMEMBER_COOKIE_SAMESITE = None - Ограничивает использование файла cookie "Запомнить меня" контекстом собственного сайта или контекстом того же сайта.

Защита сеанса Flask-Login

Несмотря на то, что описанные выше функции помогают защитить токен "Запомнить меня" от похитителей, файлы cookie сеанса по-прежнему уязвимы. Flask-Login включает защиту сеансов, которая помогает предотвратить кражу сеансов пользователей.

Можно настроить защиту сеанса в flask_login.LoginManager и в конфигурации приложения. Если защита включена, то она может работать как в базовом, так и в усиленном режиме. Во flask_login.LoginManager она устанавливается для атрибута LoginManager.session_protection в значение 'basic' или 'strong':

login_manager.session_protection = "strong"

# или, что-бы отключить
login_manager.session_protection = None

По умолчанию защита активирована в режиме "basic". Её можно переопределить в конфигурации приложения, установив для параметра SESSION_PROTECTION значение None, "basic" или "strong".

Когда защита сеанса активна, при каждом запросе генерируется идентификатор компьютера пользователя (по сути, безопасный хэш IP-адреса и пользовательского агента). Если сеанс не имеет связанного идентификатора, то будет сохранен сгенерированный. Если у него есть идентификатор и он соответствует сгенерированному, то запрос одобрен.

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

Если идентификаторы не совпадают в строгом режиме для непостоянного сеанса, то весь сеанс (а также токен, если он существует) удаляется.

Отключение сеансовых cookie для API

При аутентификации в API можно отключить настройку сеанса cookie. Для этого используйте собственный интерфейс сеанса, который пропускает сохранение сеанса в зависимости от флага, установленного в запросе. Например:

from flask import g
from flask.sessions import SecureCookieSessionInterface
from flask_login import user_loaded_from_request

@user_loaded_from_request.connect
def user_loaded_from_request(app, user=None):
    g.login_via_request = True


class CustomSessionInterface(SecureCookieSessionInterface):
    """Запретить создание сеанса на основе запросов API"""
    def save_session(self, *args, **kwargs):
        if g.get('login_via_request'):
            return
        return super(CustomSessionInterface, self).save_session(*args,
                                                                **kwargs)

app.session_interface = CustomSessionInterface()

@user_loaded_from_request.connect
def user_loaded_from_request(self, user=None):
    g.login_via_request = True

Это предотвращает установку cookie сеанса Flask каждый раз, когда пользователь проходит аутентификацию с помощью вашего LoginManager.request_loader.

Тестирование Flask-Login

Чтобы было проще писать автоматические тесты, Flask-Login предоставляет простой, настраиваемый клиентский класс FlaskLoginClient, который установит файл cookie входа пользователя. Чтобы использовать этот пользовательский класс тестового клиента, присвойте его атрибуту .test_client_class объекта приложения, например:

from flask_login import FlaskLoginClient

app.test_client_class = FlaskLoginClient

Затем, для создания тестового клиента нужно использовать метод app.test_client(). Теперь можно передать этому методу объект пользователя, и клиент автоматически войдет в систему под этим пользователем!

def test_request_with_logged_in_user():
    user = User.query.get(1)
    with app.test_client(user=user) as client:
        # В этом запросе вошел пользователь 1!
        client.get("/")

Также можно передать аргумент fresh_login (bool, по умолчанию - True), чтобы пометить текущий логин как свежий или несвежий.

Обратите внимание, что необходимо использовать ключевые слова для передачи аргументов, например, test_client(user=user) будет работать, а test_client(user) - нет.

Из-за способа реализации тестового клиентского класса, возможно, придется отключить защиту сеанса, чтобы тесты работали правильно. Если защита сеанса включена, сеансы входа в систему будут помечены как несвежие в базовом режиме или полностью отклонены в строгом режиме при выполнении запросов с тестовым клиентом.

API расширения Flask-Login

flask_login.LoginManager(app=None, add_context_processor=True):

Класс flask_login.LoginManager() используется для хранения настроек, используемых для входа в систему. Экземпляры LoginManager не привязаны к конкретным приложениям, поэтому можно создать его в основной части кода, а затем привязать его к своему приложению в фабричной функции.

Принимаемые аргументы:

  • app - объект flask.Flask для настройки.
  • add_context_processor=True - следует ли добавлять в приложение процессор контекста, который добавляет переменную current_user в шаблон.

Атрибуты и метода объекта LoginManager

  • LoginManager.init_app(app, add_context_processor=True)

    Настраивает приложение. При этом регистрируется вызов app.after_request и прикрепляется к нему LoginManager как app.login_manager.

  • LoginManager.unauthorized()

    Метод LoginManager.login_message() вызывается, когда пользователю необходимо войти в систему. Если зарегистрировать обратный вызов с помощью LoginManager.unauthorized_handler(callback), то он будет вызван. В противном случае будут предприняты следующие действия:

    • Появиться сообщение LoginManager.login_message для пользователя.
    • Если приложение использует схемы blueprint, то найдет представление входа в систему для текущей схемы с помощью LoginManager.blueprint_login_views. Если приложение не использует схемы или представление login() для текущей схемы не определено, то использует значение LoginManager.login_view.
    • Перенаправит пользователя в представление входа в систему. (Страница, к которой пользователь пытался получить доступ, будет передана в строковую переменную запроса next для последующего перенаправления после авторизации вместо страницы по умолчанию. Альтернативно, она будет добавлена ​​в сеанс как параметр next, если установлено USE_SESSION_FOR_NEXT)

    Если LoginManager.login_view не определен, то метод просто выдаст ошибку HTTP 401 (неавторизованный).

    Это значение должно быть возвращено из функции-представления или функции before/after_request, иначе перенаправление не будет иметь никакого эффекта.

  • LoginManager.needs_refresh()

    Метод LoginManager.needs_refresh() вызывается, когда пользователь входит в систему, но ему необходимо пройти повторную аутентификацию, т.к. его сеанс устарел. Если зарегистрировать обратный вызов с помощью LoginManager.needs_refresh_handler(callback), то он будет вызван. В противном случае будут предприняты следующие действия:

    • Отправит пользователю сообщение LoginManager.needs_refresh_message.
    • Перенаправит пользователя в LoginManager.refresh_view. (Страница, к которой они пытались получить доступ, будет передана в следующей строковой переменной запроса, поэтому вы можете перенаправить ее, если она присутствует, вместо домашней страницы)

    Если LoginManager.refresh_view не определен, то метод просто выдаст ошибку HTTP 401 (неавторизованный).

    Это значение должно быть возвращено из функции-представления или функции before/after_request, иначе перенаправление не будет иметь никакого эффекта.

    Дополнительно смотрите подраздел "Новые логины пользователей"

  • LoginManager.user_loader(callback)

    Метод-декоратор LoginManager.user_loader() устанавливает обратный вызов для перезагрузки пользователя из сеанса. Пользовательская функция callback должна принимать идентификатор пользователя в виде строки и возвращать объект пользователя User или None, если пользователь не существует.

    Дополнительно смотрите подраздел "Как взаимодействует Flask-Login с приложением Flask"

  • LoginManager.request_loader(callback)

    Метод-декоратор LoginManager.request_loader() устанавливает обратный вызов для загрузки пользователя из запроса Flask. Пользовательская функция обратного вызова callback должна принимать объект запроса Flask и возвращать объект пользователя User или None, если пользователь не существует.

    Дополнительно смотрите подраздел "Пользовательский вход в систему с помощью загрузчика запросов"

  • LoginManager.anonymous_user

    Принимает класс или фабричную функцию, которая создает анонимного пользователя (используется, когда никто не входит в систему). По умолчанию используется класс flask_login.AnonymousUserMixin

  • LoginManager.login_view

    Принимает имя функции-представления, на которое происходит перенаправление, когда пользователю необходимо войти в систему. (Это также может быть абсолютный URL-адрес, если механизм аутентификации является внешним по отношению к приложению.)

    Дополнительно смотрите подраздел "Настройка процесса входа в систему"

  • LoginManager.blueprint_login_views

    Похоже на LoginManager.login_view, за исключением того, что он используется при работе со схемами blueprint. Это словарь, который может хранить несколько представлений для перенаправления на разные схемы элементов. Имена схемы используются в качестве ключа, а в качестве значения перенаправления на маршрут.

  • LoginManager.login_message

    Сообщение, которое будет показано, когда пользователь перенаправляется на страницу входа.

    Дополнительно смотрите подраздел "Настройка процесса входа в систему"

  • LoginManager.unauthorized_handler(callback)

    Метод-декоратор LoginManager.unauthorized_handler() устанавливает обратный вызов для неавторизованного метода, который, помимо прочего, используется LoginManager.login_required. Пользовательская функция обратного вызова callback не принимает аргументов и должна возвращать ответ, который будет отправлен пользователю вместо его обычного представления.

    Дополнительно смотрите подраздел "Настройка процесса входа в систему"

  • LoginManager.refresh_view

    Принимает имя функции-представление для перенаправления пользователя для повторной аутентификации.

    Дополнительно смотрите подраздел "Новые логины пользователей"

  • LoginManager.needs_refresh_message

    Устанавливает сообщение, которое будет показано, когда пользователь перенаправляется на страницу повторной аутентификации.

    Дополнительно смотрите подраздел "Функция "Запомнить меня""

  • LoginManager.needs_refresh_handler(callback)

    Метод LoginManager.needs_refresh_handler() установит обратный вызов для метода LoginManager.needs_refresh(), который, помимо прочего, используется flask_login.fresh_login_required. Пользовательская функция обратного вызова callback не принимает аргументов и должна возвращать ответ, который будет отправлен пользователю вместо его обычного представления.

    Дополнительно смотрите подраздел "Функция "Запомнить меня""

Механизмы входа в систему

  • flask_login.current_user - Прокси для текущего пользователя.
  • flask_login.login_fresh() - возвращает значение True, если текущий логин является новым.
  • flask_login.login_remembered() - возвращает значение True, если текущий логин запоминается во всех сеансах.
  • flask_login.logout_user() - Завершает работу с пользователем (не нужно указывать имя реального пользователя). Это также приведет к удалению файла cookie "Запомнить меня", если он существует.
  • flask_login.confirm_login() - текущая сессия будет обновлена. Сеансы становятся устаревшими, когда они перезагружаются из файла cookie.

flask_login.login_user(user, remember=False, duration=None, force=False, fresh=True):

Функция flask_login.login_user() регистрирует пользователя. Необходимо передать ей реальный экземпляр объекта пользователя User(). Если свойство пользователя User.is_active имеет значение False, то он не войдет в систему, если аргумент force имеет значение False.

Функция flask_login.login_user() возвращает значение True, если попытка входа в систему будет успешной, и значение False, если она завершится неудачей (т.е. из-за того, что пользователь неактивен).

Принимаемые аргументы:

  • user - экземпляр объекта [пользователя User()] для входа в систему.
  • remember=False - Следует ли запоминать имя пользователя после истечения срока его сеанса.
  • duration=None (datetime.timedelta) - Время до истечения срока действия cookie для запоминания. Если None, то используется значение, заданное в настройках.
  • force=False - Если пользователь неактивен, установка значения True позволит ему войти в систему в любом случае.
  • fresh=True - установка значения False приведет к тому, что пользователь войдет в систему с сеансом, помеченным как "не свежий".

Защита представлений

flask_login.login_required(func):

Если украсить представление декоратором @login_required, то это будет гарантировать, что текущий пользователь вошел в систему и прошел аутентификацию перед вызовом фактической функции-представления. (Если это не так, он вызывает обратный вызов LoginManager.unauthorized](#flask_login.LoginManager)) Например:

@app.route('/post')
@login_required
def post():
    pass

Если нужно, чтобы пользователь входил в систему только в определенные моменты, то можно сделать это с помощью:

if not current_user.is_authenticated:
    return current_app.login_manager.unauthorized()

...который, по сути, является кодом, добавляемым этой функцией к функции-представлениям

Может быть удобно глобально отключить аутентификацию при модульном тестировании. Для включения такого поведения, нужно переменной конфигурации приложения LOGIN_DISABLED установить значение True (декоратор @login_required будет игнорироваться).

flask_login.fresh_login_required(func):

Если украсить представление декоратором @fresh_login_required, то это будет гарантировать, что логин текущего пользователя является "свежим", то есть его сеанс не был восстановлен из файла cookie. Конфиденциальные операции, такие как смена пароля или электронной почты, должны быть защищены с помощью этого декоратора.

Если пользователь не аутентифицирован, то LoginManager.unauthorized() вызывается как обычно. Если пользователь прошел аутентификацию, но его сеанс "несвежий", то будет вызван метод LoginManager.needs_refresh(). (В этом случае потребуется предоставить LoginManager.refresh_view.)

В отношении переменных конфигурации ведет себя идентично декоратору @login_required().

Функция помощник Flask-Login

flask_login.login_url(login_view, next_url=None, next_field='next'):

Функция flask_login.login_url() создает URL-адрес для перенаправления на страницу входа. Если указан только login_view, он просто вернет URL-адрес. НО если указан next_url, к строке запроса будет добавлен параметр next=URL, чтобы представление входа в систему могло перенаправить обратно на этот URL-адрес. Обработчик несанкционированных действий Flask-Login по умолчанию использует эту функцию при перенаправлении на URL-адрес входа.

Чтобы принудительно использовать имя хоста, нужно установить для FORCE_HOST_FOR_REDIRECTS хост. Это предотвращает перенаправление на внешние сайты, если SERVER_NAME не настроен.

Принимаемые аргументы:

  • login_view - Строка с именем функции-представления для входа в систему. (В качестве альтернативы фактический URL-адрес функции-представления входа в систему)
  • next_url=None - URL-адрес, предоставляющий вид входа в систему для перенаправления.
  • next_field='next' - В каком поле хранить следующий URL-адрес?

Сигналы Flask-Login

Дополнительно смотрите материал "Подписка на сигналы в приложении Flask" для получения информации о том, как использовать сигналы ниже в коде приложения.

  • flask_login.user_logged_in - Отправляется, когда пользователь входит в систему. В дополнение к приложению (которое является отправителем), оно передается пользователю, который входит в систему.
  • flask_login.user_logged_out - Отправляется, когда пользователь выходит из системы. В дополнение к приложению (которое является отправителем), оно передается пользователю, который выходит из системы
  • flask_login.user_login_confirmed - Отправляется при подтверждении входа пользователя и помечает его как новый. (Он не вызывается для обычного входа в систему.) Он не получает никаких дополнительных аргументов, кроме приложения.
  • flask_login.user_unauthorized - Отправляется при вызове метода LoginManager.unauthorized(). Он не получает никаких дополнительных аргументов, кроме приложения.
  • flask_login.user_needs_refresh - Отправляется при вызове метода LoginManager.needs_refresh(). Он не получает никаких дополнительных аргументов, кроме приложения.
  • flask_login.session_protected - Отправляется каждый раз, когда защита сеанса вступает в силу, и сеанс либо помечается как не обновленный, либо удаляется. Он не получает никаких дополнительных аргументов, кроме приложения.