Пример логина: Пример логинов

Содержание

Параметр login_hint | КриптоПро DSS

Часто клиентское приложение заранее знает логин пользователя, и было бы удобно сразу подставить значение логина в форме аутентификации. В качестве такой подсказки спецификация OpenID Connect 1.0 предлагает необязательный параметр login_hint.

Данный параметр представляет собой подсказку для Центра Идентификации, которую он использует на странице аутентификации. Если указанный параметр передан и пользователь с таким логином зарегистрирован и не заблокирован в DSS, то его значение будет использовано в качестве логина, тем самым пользователю останется только ввести свой пароль. Если же пользователя с таким логином нет или его учётная запись заблокирована, то параметр будет проигнорирован.

Параметр login_hint определён для двух сценариев: с использованием кода авторизации и с неявным разрешением (см. Authorization Code Flow и Implicit Flow).

Примеры запросов

Рассмотрим пример запроса, содержащего параметр login_hint

(переносы строк добавлены для наглядности):

GET /authorize?
    client_id=eea2fd3f-5c70-4d74-a594-f1e7bf81b4d7
    &resource=https:%2f%2fdss. cryptopro.ru%2fSignServer%2frest%2fapi
    &redirect_uri=http:%2f%2f127.0.0.1:9158%2f
    &response_type=code
    &login_hint=sga HTTP/1.1
Host: dss.cryptopro.ru

Получение имени пользователя из id_token

Клиентское приложение может получить имя пользователя из id_token. Рассмотрим пример содержимого id_token:

{
  "unique_name": "sga",
  "dss_iss": "realsts",
  "dss_uuid": "49pDZfxUwFjeHhYSsrSX2LvdSxA=",
  "role": "Users",
  "dss_group": "Default",
  "at_hash": "yQAbEebC9sgmXrjonanKPQ",
  "iss": "realsts",
  "aud": "cryptopro.cloud.csp",
  "exp": 1527844466,
  "nbf": 1527844166
}

В id_token логин пользователя содержится в утверждении unique_name. В данном примере это sga. Однако клиентскому приложению следует обратить внимание не только на значение этого утверждения, но и на значение утверждения dss_iss. В нём содержится идентификатор Центра Идентификации, осуществившего аутентификацию пользователя. Использовать значение unique_name в качестве параметра login_hint

можно только в случае, если dss_iss равен realsts. Значение realsts говорит о том, что в unique_name находится логин пользователя в ЦИ DSS, а не логин из стороннего ЦИ. Например, unique_name из такого маркера использовать нельзя:

{
  "unique_name": "[email protected]",
  "dss_iss": "adfs",
  "dss_uuid": "49pDZfxUwFjeHhYSsrSX2LvdSxA=",
  "role": "Users",
  "dss_group": "Default",
  "at_hash": "yQAbEebC9sgmXrjonanKPQ",
  "iss": "realsts",
  "aud": "cryptopro.cloud.csp",
  "exp": 1527844466,
  "nbf": 1527844166
}

Руководство Django Часть 8: Аутентификация и авторизация пользователя — Изучение веб-разработки

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

(permissions). Для того чтобы продемонстрировать все это, мы расширим LocalLibrary, добавив страницы для входа/выхода, а также страницы просмотра/редактирования книг, специфические для пользователя и персонала.

Требования:Завершить изучение предыдущих тем руководства, включая Руководство Django Часть 7: Работа с сессиями.
Цель:Понимать как настроить и использовать механизм аутентификации пользователя и разграничений прав доступа.

Django предоставляет систему аутентификации и авторизации («permission») пользователя, реализованную на основе фреймворка работы с сессиями, который мы рассматривали в предыдущей части. Система аутентификации и авторизации позволяет вам проверять учётные данные пользователей и определять какие действия какой пользователь может выполнять. Данный фреймворк включает в себя встроенные модели для Пользователей и Групп (основной способ применения прав доступа для более чем одного пользователя), непосредственно саму систему прав доступа (permissions)/флаги, которые определяют может ли пользователь выполнить задачу, с какой формой и отображением для авторизованных пользователей, а так же получить доступ к контенту с ограниченным доступом.

Примечание: В соответствии с идеологией Django система аутентификации является очень общей и, таким образом, не предоставляет некоторые возможности, которые присутствуют в других системах веб-аутентификации. Решениями некоторых общих задач занимаются пакеты сторонних разработчиков, например, защита от подбора пароля (через стороннюю библиотеку OAuth).

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

Система аутентификации является очень гибкой и позволяет вам формировать свои собственные URL-адреса, формы, отображения, а также шаблоны страниц, если вы пожелаете, с нуля, через простой вызов функций соответствующего API для авторизации пользователя.

Тем не менее, в данной статье мы будем использовать «встроенные» в Django методы отображений и форм аутентификации, а также методы построения страниц входа и выхода. Нам все ещё необходимо создавать шаблоны страниц, но это будет достаточно несложно.

Мы покажем вам как реализовать разграничение доступа (permissions), а также выполнять соответствующую проверку статусов авторизации и прав доступа, в отображениях, и в шаблонах страниц.

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

Примечание: Необходимые настройки были выполнены для нас, когда мы создали приложение при помощи команды

django-admin startproject. Таблицы базы данных для пользователей и модели авторизации были созданы, когда в первый раз выполнили команду python manage.py migrate.

Соответствующие настройки сделаны в параметрах INSTALLED_APPS и MIDDLEWARE файла проекта (locallibrary/locallibrary/settings. py), как показано ниже:

INSTALLED_APPS = [
    ...
    'django.contrib.auth',  
    'django.contrib.contenttypes',  
    ....

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',  
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',  
    ....

Вы уже создали своего первого пользователя когда мы рассматривали Административная панель сайта Django в части 4 (это был суперпользователь, созданный при помощи команды python manage.py createsuperuser). Наш суперпользователь уже авторизован и имеет все необходимые уровни доступа к данным и функциям, таким образом нам необходимо создать тестового пользователя для отработки соответствующей работы сайта. В качестве наиболее быстрого способа, мы будем использовать административную панель сайта для создания соответствующих групп и аккаунтов locallibrary.

Примечание: вы можете создавать пользователей программно, как показано ниже. Например, вам мог бы подойти данный способ в том случае, если вы разрабатываете интерфейс, который позволяет пользователям создавать их собственные аккаунты (вы не должны предоставлять доступ пользователям к административной панели вашего сайта).

from django.contrib.auth.models import User


user = User.objects.create_user('myusername', '[email protected]', 'mypassword')


user.first_name = 'John'
user.last_name = 'Citizen'
user.save()

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

Запустите сервер разработки и перейдите к административной панели вашего сайта (http://127.0.0.1:8000/admin/). Залогиньтесь на сайте при помощи параметров (имя пользователя и пароля) аккаунта суперпользователя. Самая «верхняя» страница панели Администратора показывает все наши модели. Для того, чтобы увидеть записи в разделе Authentication and Authorisation вы можете нажать на ссылку

Users, или Groups.

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

  1. Нажмите на кнопку Add (Добавить) (рядом с Group) и создайте новую группу; для данной группы введите Name (Имя) «Library Members».
  2. Для данной группы не нужны какие-либо разрешения, поэтому мы просто нажимаем кнопку SAVE (Сохранить) (вы перейдёте к списку групп).

Теперь давайте создадим пользователя:

  1. Перейдите обратно на домашнюю страницу административной панели
  2. Для перехода к диалогу добавления пользователя нажмите на кнопку Add, соответствующую строке Users (Пользователи).
  3. Введите соответствующие Username (имя пользователя) и Password/Password confirmation (пароль/подтверждение пароля) для вашего тестового пользователя
  4. Нажмите SAVE для завершения процесса создания пользователя.

    Административная часть сайта создаст нового пользователя и немедленно перенаправит вас на страницу Change user (Изменение параметров пользователя) где вы можете, соответственно, изменить ваш username, а кроме того добавить информацию для дополнительных полей модели User. Эти поля включают в себя имя пользователя, фамилию, адрес электронной почты, статус пользователя, а также соответствующие параметры доступа (может быть установлен только флаг  Active). Ниже вы можете определить группу для пользователя и необходимые параметры доступа, а кроме того, вы можете увидеть важные даты, относящиеся к пользователю (дату подключения к сайту и дату последнего входа).

  5. В разделе Groups, из списка Доступные группы выберите группу Library Member, а затем переместите её в блок «Выбранные группы» (нажмите стрелку-«направо», находящуюся между блоками).
  6. Больше нам не нужно здесь нечего делать, просто нажмите «Save»(Сохранить), и вы вернётесь к списку созданных пользователей.

Вот и все! Теперь у вас есть учётная запись «обычного члена библиотеки», которую вы сможете использовать для тестирования (как только добавим страницы, чтобы пользователи могли войти в систему).

Note: Попробуйте создать другого пользователя, например «Библиотекаря». Так же создайте группу «Библиотекарей» и добавьте туда своего только что созданного библиотекаря

Django предоставляет почти все, что нужно для создания страниц аутентификации входа, выхода из системы и управления паролями из коробки. Это включает в себя url-адреса, представления (views) и формы,но не включает шаблоны — мы должны создать свой собственный шаблон!

В этом разделе мы покажем, как интегрировать систему по умолчанию в Сайт LocalLibrary и создать шаблоны.  Мы поместим их в основные URL проекта.

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

Примечание: В этом случае мы могли бы разумно поместить страницы аутентификации, включая URL-адреса и шаблоны, в наше приложение каталога. Однако, если бы у нас было несколько приложений, было бы лучше отделить это общее поведение входа в систему и иметь его доступным на всем сайте, так что это то, что мы показали здесь!

Проектирование URLs

Добавьте следующее в нижней части проекта urls.py файл (locallibrary/locallibrary/urls.py) файл:


urlpatterns += [
    path('accounts/', include('django.contrib.auth.urls')),
]

Перейдите по http://127.0.0.1:8000/accounts/ URL (обратите внимание на косую черту!), Django покажет ошибку, что он не смог найти этот URL, и перечислить все URL, которые он пытался открыть. Из этого вы можете увидеть URL-адреса, которые будут работать, например:

Примечание. Использование вышеуказанного метода добавляет следующие URL-адреса с именами в квадратных скобках, которые могут использоваться для изменения сопоставлений URL-адресов. Вам не нужно реализовывать что-либо ещё — приведённое выше сопоставление URL-адресов автоматически отображает указанные ниже URL-адреса.

accounts/ login/ [name='login']
accounts/ logout/ [name='logout']
accounts/ password_change/ [name='password_change']
accounts/ password_change/done/ [name='password_change_done']
accounts/ password_reset/ [name='password_reset']
accounts/ password_reset/done/ [name='password_reset_done']
accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/ reset/done/ [name='password_reset_complete']

Теперь попробуйте перейти к URL-адресу входа (http://127.0.0.1:8000/accounts/login/). Это приведёт к сбою снова, но с ошибкой, сообщающей вам, что нам не хватает требуемого шаблона (registration / login.html) в пути поиска шаблона. Вы увидите следующие строки, перечисленные в жёлтом разделе вверху:

Exception Type:    TemplateDoesNotExist
Exception Value:    registration/login.html

Следующий шаг — создать каталог регистрации в пути поиска, а затем добавить файл login. html.

Каталог шаблонов

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

Для этого сайта мы разместим наши HTML-страницы в каталоге templates / registration /. Этот каталог должен находиться в корневом каталоге проекта, то есть в том же каталоге, что и в каталоге и папках locallibrary). Создайте эти папки сейчас.

Примечание: ваша структура папок теперь должна выглядеть как показано внизу:
locallibrary (django project folder)
   |_catalog
   |_locallibrary
   |_templates (new)
                |_registration

Чтобы сделать эти директории видимыми для загрузчика шаблонов   (т. е. помещать этот каталог в путь поиска шаблона) откройте настройки проекта (/locallibrary/locallibrary/settings.py), и обновите в секции TEMPLATES строку 'DIRS' как показано.

TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        ...

Шаблон аутентификации

Важно: Шаблоны аутентификации, представленные в этой статье, являются очень простой / слегка изменённой версией шаблонов логина демонстрации Django. Возможно, вам придётся настроить их для собственного использования!

Создайте новый HTML файл, названный /locallibrary/templates/registration/login.html. дайте ему следующее содержание:

{% extends "base_generic.html" %}

{% block content %}

{% if form.errors %}
  <p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
  {% if user.is_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
  {% else %}
    <p>Please login to see this page.</p>
  {% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>

<tr>
  <td>{{ form. username.label_tag }}</td>
  <td>{{ form.username }}</td>
</tr>

<tr>
  <td>{{ form.password.label_tag }}</td>
  <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>

{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

Этот шаблон имеет сходство с тем, что мы видели раньше — он расширяет наш базовый шаблон и переопределяет блок контента. Остальная часть кода — это довольно стандартный код обработки формы, о котором мы поговорим в следующем учебном пособии. Все, что вам нужно знать, это показ формы, в которой вы можете ввести своё имя пользователя и пароль, а если вы введёте недопустимые значения, вам будет предложено ввести правильные значения, когда страница обновится.

Перейдите на страницу входа (http://127. 0.0.1:8000/accounts/login/) когда вы сохраните свой шаблон, и вы должны увидеть что-то наподобие этого:

Если ваша попытка войти в систему будет успешной,  вы будете перенаправлены на другую страницу (по умолчанию это будет http://127.0.0.1:8000/accounts/profile/). Проблема здесь в том, что по умолчанию Django ожидает, что после входа в систему вы захотите перейти на страницу профиля, что может быть или не быть. Поскольку вы ещё не определили эту страницу, вы получите ещё одну ошибку!

Откройте настройки проекта (/locallibrary/locallibrary/settings.py) и добавьте текст ниже. Теперь, когда вы входите в систему, вы по умолчанию должны перенаправляться на домашнюю страницу сайта.

Шаблон выхода

Если вы перейдёте по URL-адресу выхода (http://127.0.0.1:8000/accounts/logout/), то увидите странное поведение — ваш пользователь наверняка выйдет из системы, но вы попадёте на страницу выхода администратора. Это не то, что вам нужно, хотя бы потому, что ссылка для входа на этой странице приведёт вас к экрану входа в систему администратора. (и это доступно только для пользователей, у которых есть разрешение is_staff).

Создайте и откройте /locallibrary/templates/registration/logged_out.html. Скопируйте текст ниже:

{% extends "base_generic.html" %}

{% block content %}
<p>Logged out!</p>

<a href="{% url 'login'%}">Click here to login again.</a>
{% endblock %}

Этот шаблон очень прост. Он просто отображает сообщение, информирующее вас о том, что вы вышли из системы, и предоставляет ссылку, которую вы можете нажать, чтобы вернуться на экран входа в систему. Если вы снова перейдёте на страницу выхода из системы, вы увидите эту страницу:

Шаблон сброса пароля

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

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

Форма сброса пароля

Это форма, используемая для получения адреса электронной почты пользователя (для отправки пароля для сброса пароля). Создайте /locallibrary/templates/registration/password_reset_form.html и дайте ему следующее содержание:

{% extends "base_generic.html" %}
{% block content %}

<form action="" method="post">{% csrf_token %}
    {% if form.email.errors %} {{ form.email.errors }} {% endif %}
        <p>{{ form.email }}</p>
    <input type="submit" value="Reset password" />
</form>

{% endblock %}
Сброс пароля

Эта форма отображается после того, как ваш адрес электронной почты будет собран. Создайте /locallibrary/templates/registration/password_reset_done.html, и дайте ему следующее содержание:

{% extends "base_generic.html" %}
{% block content %}
<p>We've emailed you instructions for setting your password.  If they haven't arrived in a few minutes, check your spam folder.</p>
{% endblock %}
Сброс пароля по email

Этот шаблон предоставляет текст электронной почты HTML, содержащий ссылку на сброс, которую мы отправим пользователям. Создайте /locallibrary/templates/registration/password_reset_email.html и дайте ему следующее содержание:

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
Подтверждение на сброс пароля

На этой странице вы вводите новый пароль после нажатия ссылки в электронном письме с возвратом пароля. Создайте /locallibrary/templates/registration/password_reset_confirm.html и дайте ему следующее содержание:

{% extends "base_generic.html" %}

{% block content %}

    {% if validlink %}
        <p>Please enter (and confirm) your new password.</p>
        <form action="" method="post">
            {% csrf_token %}
            <table>
                <tr>
                    <td>{{ form. new_password1.errors }}
                        <label for="id_new_password1">New password:</label></td>
                    <td>{{ form.new_password1 }}</td>
                </tr>
                <tr>
                    <td>{{ form.new_password2.errors }}
                        <label for="id_new_password2">Confirm password:</label></td>
                    <td>{{ form.new_password2 }}</td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="Change my password" /></td>
                </tr>
            </table>
        </form>
    {% else %}
        <h2>Password reset failed</h2>
        <p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
    {% endif %}

{% endblock %}
Сброс пароля завершён

Это последний шаблон сброса пароля, который отображается, чтобы уведомить вас о завершении сброса пароля. Создайте /locallibrary/templates/registration/password_reset_complete.html и дайте ему следующее содержание:

{% extends "base_generic.html" %}
{% block content %}

<h2>The password has been changed!</h2>
<p><a href="{% url 'login' %}">log in again?</a></p>

{% endblock %}

Тестирование новых страниц аутентификации

Теперь, когда вы добавили конфигурацию URL и создали все эти шаблоны, теперь страницы аутентификации должны работать! Вы можете протестировать новые страницы аутентификации, попытавшись войти в систему, а затем выйдите из учётной записи суперпользователя, используя эти URL-адреса:

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

Примечание: Система сброса пароля требует, чтобы ваш сайт поддерживал электронную почту, что выходит за рамки этой статьи, поэтому эта часть ещё не будет работать. Чтобы разрешить тестирование, поместите следующую строку в конец файла settings.py. Это регистрирует любые письма, отправленные на консоль (чтобы вы могли скопировать ссылку на сброс пароля с консоли).

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Для получения дополнительной информации см. Отправка email (Django docs).

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

Тестирование в шаблонах

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

Обычно вы сначала проверяете переменную шаблона {{user.is_authenticated}}, чтобы определить, имеет ли пользователь право видеть конкретный контент. Чтобы продемонстрировать это, мы обновим нашу боковую панель, чтобы отобразить ссылку «Вход», если пользователь вышел из системы, и ссылку «Выход», если он вошёл в систему.

Откройте базовый шаблон (/locallibrary/catalog/templates/base_generic.html) и скопируйте следующий текст в sidebar блок непосредственно перед тегом шаблона endblock.

  <ul>

    ...

   {% if user.is_authenticated %}
     <li>User: {{ user.get_username }}</li>
     <li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
   {% else %}
     <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
   {% endif %} 
  </ul>

Как вы можете видеть, мы используем теги шаблона if-else-endif для условного отображения текста на основе того, является ли {{user.is_authenticated}} истинным. Если пользователь аутентифицирован, мы знаем, что у нас есть действительный пользователь, поэтому мы вызываем {{user.get_username}}, чтобы отобразить их имя.

Мы создаём URL-адрес для входа и выхода из системы, используя тег шаблона URL-адреса и имена соответствующих конфигураций URLs.  Также обратите внимание на то, как мы добавили ?next={{request.path}} в конец URLs. Это означает, что следующий URL-адрес содержит адрес (URL) текущей страницы, в конце связанного URL-адреса. После того, как пользователь успешно выполнил вход в систему, представления будут использовать значение «next» чтобы перенаправить пользователя обратно на страницу, где они сначала нажали ссылку входа / выхода из системы.

Примечание: Попробуйте! Если вы находитесь на главной странице и вы нажимаете «Вход / Выход» на боковой панели, то после завершения операции вы должны вернуться на ту же страницу.

Тестирование в представлениях

Если вы используете функциональные представления, самым простым способом ограничить доступ к вашим функциям является применение login_required декоратор к вашей функции просмотра, как показано ниже. Если пользователь вошёл в систему, ваш код просмотра будет выполняться как обычно. Если пользователь не вошёл в систему, это перенаправит URL-адрес входа, определённый в настройках проекта. (settings.LOGIN_URL), передав текущий абсолютный путь в качестве next параметра URL. Если пользователю удастся войти в систему, они будут возвращены на эту страницу, но на этот раз аутентифицированы.

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

Примечание: Вы можете сделать то же самое вручную, путём тестирования request.user.is_authenticated, но декоратор намного удобнее!

Аналогичным образом, самый простой способ ограничить доступ к зарегистрированным пользователям в ваших представлениях на основе классов — это производные от LoginRequiredMixin. Вы должны объявить этот mixin сначала в списке суперкласса, перед классом основного представления.

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    ...

Это имеет такое же поведение при переадресации, что и  login_required декоратор.  Вы также можете указать альтернативное местоположение для перенаправления пользователя, если он не аутентифицирован (login_url), и имя параметра URL вместо «next» , чтобы вставить текущий абсолютный путь (redirect_field_name).

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

Для получения дополнительной информации ознакомьтесь с  Django docs here.

Теперь, когда мы знаем, как ограничить страницу определённому пользователю, создайте представление о книгах, которые заимствовал текущий пользователь.

К сожалению, у нас пока нет возможности пользователям использовать книги! Поэтому, прежде чем мы сможем создать список книг, мы сначала расширим BookInstance модель для поддержки концепции заимствования и использования приложения Django Admin для заимствования ряда книг нашему тестовому пользователю.

Модели

Прежде всего, мы должны предоставить пользователям возможность кредита на BookInstance (у нас уже есть status и due_back дата, но у нас пока нет связи между этой моделью и пользователем. Мы создадим его с помощью поля ForeignKey (один ко многим). Нам также нужен простой механизм для проверки того, просрочена ли заёмная книга.

Откройте catalog/models.py, и импортируйте модель User из django.contrib.auth.models (добавьте это чуть ниже предыдущей строки импорта в верхней части файла, так User доступен для последующего кода, что позволяет использовать его):

from django.contrib.auth.models import User

Затем добавьте поле borrower в модель BookInstance:

borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)

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

from datetime import date

Теперь добавьте следующее определение свойства внутри класса BookInstance:

@property
def is_overdue(self):
    if self. due_back and date.today() > self.due_back:
        return True
    return False

Примечание. Сначала мы проверим, является ли due_back пустым, прежде чем проводить сравнение. Пустое поле due_back заставило Django выкидывать ошибку, а не показывать страницу: пустые значения не сопоставимы. Это не то, что мы хотели бы, чтобы наши пользователи испытывали!

Теперь, когда мы обновили наши модели, нам нужно будет внести новые изменения в проект, а затем применить эти миграции:

python3 manage.py makemigrations
python3 manage.py migrate

Admin

Теперь откройте каталог catalog/admin.py, и добавьте поле borrower в класс BookInstanceAdmin , как в list_display , так и в полях fieldsets , как показано ниже. Это сделает поле видимым в разделе Admin, так что мы можем при необходимости назначить User в BookInstance.

@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    list_display = ('book', 'status', 'borrower', 'due_back', 'id')
    list_filter = ('status', 'due_back')

    fieldsets = (
        (None, {
            'fields': ('book','imprint', 'id')
        }),
        ('Availability', {
            'fields': ('status', 'due_back','borrower')
        }),
    )

Займите несколько книг

Теперь, когда возможно кредитовать книги конкретному пользователю, зайдите и заработайте на нескольких записей в BookInstance. Установите borrowed поле вашему тестовому пользователю, сделайте status «В займе» и установите сроки оплаты как в будущем, так и в прошлом.

Примечание: Мы не будем описывать процесс, так как вы уже знаете, как использовать Admin сайт!

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

Теперь мы добавим представление для получения списка всех книг, которые были предоставлены текущему пользователю. Мы будем использовать один и тот же общий класс, с которым мы знакомы, но на этот раз мы также будем импортировать и выводить из  LoginRequiredMixin, так что только вошедший пользователь сможет вызвать это представление. Мы также решили объявить  template_name, вместо того, чтобы использовать значение по умолчанию, потому что у нас может быть несколько разных списков записей BookInstance, с разными представлениями и шаблонами.

Добавьте следующее в catalog/views.py:

from django.contrib.auth.mixins import LoginRequiredMixin

class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
    """
    Generic class-based view listing books on loan to current user.
    """
    model = BookInstance
    template_name ='catalog/bookinstance_list_borrowed_user.html'
    paginate_by = 10

    def get_queryset(self):
        return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')

Чтобы ограничить наш запрос только объектами BookInstance для текущего пользователя, мы повторно реализуем get_queryset(), как показано выше. mybooks/$’, views.LoanedBooksByUserListView.as_view(), name=’my-borrowed’), ]

Шаблон для заёмных книг

Теперь все, что нам нужно сделать для этой страницы, — это добавить шаблон. Сначала создайте файл шаблона /catalog/templates/catalog/bookinstance_list_borrowed_user.html и дайте ему следующее содержание:

{% extends "base_generic.html" %}

{% block content %}
    <h2>Borrowed books</h2>

    {% if bookinstance_list %}
    <ul>

      {% for bookinst in bookinstance_list %}
      <li>
        <a href="{% url 'book-detail' bookinst.book.pk %}">{{bookinst.book.title}}</a> ({{ bookinst.due_back }})
      </li>
      {% endfor %}
    </ul>

    {% else %}
      <p>There are no books borrowed.</p>
    {% endif %}
{% endblock %}

Этот шаблон очень похож на тот, который мы создали ранее для объектов Book и Author. Единственное, что «новое» здесь, это то, что мы проверяем метод, который мы добавили в модель (bookinst. is_overdue) с целью использовать его для изменения цвета просроченных предметов.

Когда сервер разработки запущен, вы должны теперь иметь возможность просматривать список для зарегистрированного пользователя в своём браузере по адресу  http://127.0.0.1:8000/catalog/mybooks/. Попробуйте это, когда ваш пользователь войдёт в систему и выйдет из системы (во втором случае вы должны быть перенаправлены на страницу входа в систему).

Добавить список на боковую панель

Последний шаг — добавить ссылку на эту новую страницу в sidebar. Мы поместим это в тот же раздел, где мы покажем другую информацию для зарегистрированного пользователя.

Откройте базовый шаблон (/locallibrary/catalog/templates/base_generic.html) и добавьте выделенную строку из sidebar, как показано на рисунке.

 <ul>
   {% if user.is_authenticated %}
   <li>User: {{ user.get_username }}</li>
   <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li>
   <li><a href="{% url 'logout'%}?next={{request. path}}">Logout</a></li>
   {% else %}
   <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
   {% endif %}
 </ul>

На что это похоже?

Когда любой пользователь войдёт в систему, он будет видеть ссылку «Мной позаимствовано (My Borrowed)» в боковой колонке, и список книг, показанных ниже (первая книга не имеет установленной даты, что является ошибкой, которую мы надеемся исправить в более позднем уроке!).

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

Модели

Определение разрешений выполняется в разделе моделей «class Meta» , используется permissions поле. Вы можете указать столько разрешений, сколько необходимо в кортеже, причём каждое разрешение определяется во вложенном кортеже, содержащем имя разрешения и отображаемое значение разрешения. Например, мы можем определить разрешение, позволяющее пользователю отметить, что книга была возвращена, как показано здесь:

class BookInstance(models.Model):
    ...
    class Meta:
        ...
        permissions = (("can_mark_returned", "Set book as returned"),)   

Затем мы могли бы назначить разрешение группе «Библиотекарь» (Librarian) на сайте администратора.

Откройте catalog/models.py, и добавьте разрешение, как показано выше. Вам нужно будет повторно выполнить миграцию (вызвав python3 manage.py makemigrations и python3 manage.py migrate) для надлежащего обновления базы данных.

Шаблоны

Разрешения текущего пользователя хранятся в переменной шаблона, называемой  {{ perms }}. Вы можете проверить, имеет ли текущий пользователь определённое разрешение, используя конкретное имя переменной в соответствующем приложении «Django» — например, {{ perms.catalog.can_mark_returned }} будет True если у пользователя есть это разрешение, а False — в противном случае. Обычно мы проверяем разрешение с использованием шаблона {% if %}, как показано в:

{% if perms.catalog.can_mark_returned %}
    <!-- We can mark a BookInstance as returned. -->
    <!-- Perhaps add code to link to a "book return" view here. -->
{% endif %}

Представления

Разрешения можно проверить в представлении функции, используя  permission_required декоратор или в представлении на основе классов, используя PermissionRequiredMixin. шаблон и поведение такие же, как для аутентификации входа в систему, хотя, конечно, вы можете разумно добавить несколько разрешений.

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

from django.contrib.auth.decorators import permission_required

@permission_required('catalog.can_mark_returned')
@permission_required('catalog.can_edit')
def my_view(request):
    ...

Требуется разрешение mixin для представлений на основе классов.

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'catalog.can_mark_returned'
    
    permission_required = ('catalog.can_mark_returned', 'catalog.can_edit')
    
    

Пример

Мы не будем обновлять LocalLibrary здесь; возможно, в следующем уроке!

 Ранее в этой статье мы показали вам, как создать страницу для текущего пользователя, в которой перечислены книги, которые они заимствовали. Теперь задача состоит в том, чтобы создать аналогичную страницу, которая видна только для библиотекарей, которая отображает  все книги, которые были заимствованы, и которая показывает имя каждого заёмщика.

 Вы должны следовать той же схеме, что и для другого представления. Главное отличие состоит в том, что вам нужно ограничить представление только библиотекарями. Вы можете сделать это на основе того, является ли пользователь сотрудником (декоратор функции:  staff_member_required, переменная шаблона: user.is_staff) но мы рекомендуем вам вместо этого использовать  can_mark_returned разрешения и PermissionRequiredMixin, как описано в предыдущем разделе.

Важно: Не забудьте использовать вашего суперпользователя для тестирования на основе разрешений (проверки разрешений всегда возвращают true для суперпользователей, даже если разрешение ещё не определено!). Вместо этого создайте пользователя-библиотекаря и добавьте необходимые возможности.

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

 Отличная работа — теперь вы создали веб-сайт, на котором участники библиотеки могут входить в систему и просматривать собственный контент, и библиотекари (с правом доступа) могут просматривать все заёмные книги с их читателями. На данный момент мы все ещё просто просматриваем контент, но те же принципы и методы используются, когда вы хотите начать изменять и добавлять данные.

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

Добавление аутентификации в ваше приложение с помощью Flask-Login

Введение

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

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

В этой статье мы затронем следующие вопросы:

  • Использование библиотеки Flask-Login для управления сеансами
  • Использование встроенной утилиты Flask для хэширования паролей
  • Добавление в приложение защищенных страниц для пользователей, не выполнивших вход
  • Использование Flask-SQLAlchemy для создания пользовательской модели
  • Создание форм регистрации и входа для создания учетных записей пользователей и входа
  • Вывод пользователям сообщений об ошибках, если что-то идет не так
  • Использование информации учетной записи пользователя для отображения на странице профиля

Исходный код этого проекта доступен на GitHub.

Предварительные требования

Для этого обучающего модуля вам потребуется следующее:

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

Здесь имеется схема, которая поможет понять, как будет выглядеть структура файлов проекта после завершения прохождения учебного модуля:

.
└── flask_auth_app
    └── project
        ├── __init__.py       # setup our app
        ├── auth.py           # the auth routes for our app
        ├── db.sqlite         # our database
        ├── main.py           # the non-auth routes for our app
        ├── models.py         # our user model
        └── templates
            ├── base.html     # contains common layout and links
            ├── index.html    # show the home page
            ├── login.html    # show the login form
            ├── profile.html  # show the profile page
            └── signup.html   # show the signup form

По мере выполнения этого учебного модуля мы будем создавать эти каталоги и файлы.

Шаг 1 — Установка пакетов

Для нашего проекта нам потребуется три основных проекта:

  • Flask
  • Flask-Login: для обработки пользовательских сеансов после аутентификации
  • Flask-SQLAlchemy: для представления пользовательской модели и интерфейса с нашей базой данных

Мы будем использовать SQLite, чтобы не устанавливать дополнительные зависимости для базы данных.

Для начала мы создадим каталог проекта:

Затем нам нужно будет перейти в каталог проекта:

Если у нас нет среды Python, нам нужно будет ее создать. В зависимости от способа установки Python на вашем компьютере команды будут выглядеть примерно так:

  • python3 -m venv auth
  • source auth/bin/activate

Примечание. Вы можете использовать учебный модуль по вашей локальной среде для получения информации по настройке venv.

Выполните в своей виртуальной среде следующие команды для установки необходимых пакетов:

  • pip install flask flask-sqlalchemy flask-login

Мы установили пакеты и теперь можем создать основной файл приложения.

Шаг 2 — Создание главного файла приложения

Для начала мы создадим каталог проекта:

В первую очередь мы начнем работать над файлом __init__.py для нашего проекта:

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

project/__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# init SQLAlchemy so we can use it later in our models
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)

    app.config['SECRET_KEY'] = 'secret-key-goes-here'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'

    db.init_app(app)

    # blueprint for auth routes in our app
    from .auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint)

    # blueprint for non-auth parts of app
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app

Теперь у нас готов основной файл приложения, и мы можем начать добавление маршрутов.

Шаг 3 — Добавление маршрутов

Для наших маршрутов мы будем использовать два проекта. В основном проекте у нас будет главная страница (/) и страница профиля (/profile), открываемая после входа. Если пользователь попытается получить доступ к странице профиля без входа в систему, он будет направлен на маршрут входа.

В нашем проекте auth у нас будут маршруты для получения страницы входа (/login) и страницы регистрации (/sign-up). Также у нас имеются маршруты для обработки запросов POST от обоих этих маршрутов. Наконец, у нас имеется маршрут выхода (/logout) для выхода активного пользователя из системы.

Пока что мы определим login, signup и logout простыми возвратами. Мы вернемся к ним немного позднее и обновим их, добавив желаемые функции.

Вначале создайте файл main.py для main_blueprint:

project/main.py

from flask import Blueprint
from . import db

main = Blueprint('main', __name__)

@main.route('/')
def index():
    return 'Index'

@main.route('/profile')
def profile():
    return 'Profile'

Затем создайте файл auth.py для auth_blueprint:

project/auth.py

from flask import Blueprint
from . import db

auth = Blueprint('auth', __name__)

@auth.route('/login')
def login():
    return 'Login'

@auth.route('/signup')
def signup():
    return 'Signup'

@auth.route('/logout')
def logout():
    return 'Logout'

В терминале вы можете задать значения FLASK_APP и FLASK_DEBUG:

  • export FLASK_APP=project
  • export FLASK_DEBUG=1

Переменная среды FLASK_APP сообщает Flask, как загружать приложение. Она должна указывать на место создания create_app. Для наших целей мы будем использовать указатели на каталог project.

Переменная среды FLASK_DEBUG активируется посредством присвоения ей значения 1. Это активирует отладчик, который будет отображать в браузере ошибки приложения.

Убедитесь, что вы находитесь в каталоге flask_auth_app и запустите проект:

Теперь у вас должна появиться возможность открыть в браузере пять возможных URL-адресов и увидеть возвращаемый текст, определенный в файлах auth.py и main.py.

Например, если открыть адрес localhost:5000/profile, появится: Profile:

Мы проверили поведение наших маршрутов и можем перейти к созданию шаблонов.

Шаг 4 — Создание шаблонов

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

  • index.html
  • profile.html
  • login.html
  • signup.html

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

Для начала создайте каталог templates в каталоге project:

  • mkdir -p project/templates

Затем создайте base.html:

  • nano project/templates/base.html

Добавьте следующий код в файл base.html:

project/templates/base.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Flask Auth Example</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
</head>

<body>
    <section>

        <div>
            <nav>
                <div>

                    <div>
                        <div>
                            <a href="{{ url_for('main.index') }}">
                                Home
                            </a>
                            <a href="{{ url_for('main.profile') }}">
                                Profile
                            </a>
                            <a href="{{ url_for('auth.login') }}">
                                Login
                            </a>
                            <a href="{{ url_for('auth.signup') }}">
                                Sign Up
                            </a>
                            <a href="{{ url_for('auth.logout') }}">
                                Logout
                            </a>
                        </div>
                    </div>
                </div>
            </nav>
        </div>

        <div>
            <div>
               {% block content %}
               {% endblock %}
            </div>
        </div>
    </section>
</body>

</html>

Этот код создаст серию ссылок меню на каждую страницу приложения, а также область, где будет отображаться контент.

Примечание. За кулисами мы используем Bulma для работы со стилями и макетом. Чтобы узнать больше о Bulma, ознакомьтесь с официальной документацией Bulma.

Затем создайте файл templates/index.html:

  • nano project/templates/index.html

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

project/templates/index.html

{% extends "base.html" %}

{% block content %}
<h2>
  Flask Login Example
</h2>
<h3>
  Easy authentication and authorization in Flask.
</h3>
{% endblock %}

Этот код создаст базовую страницу указателя с заголовком и подзаголовком.

Затем создайте страницу templates/login.html:

  • nano project/templates/login.html

Этот код генерирует страницу входа с полями Email и Password. Также имеется поле для отметки запоминания сеанса входа.

project/templates/login.html

{% extends "base.html" %}

{% block content %}
<div>
    <h4>Login</h4>
    <div>
        <form method="POST" action="/login">
            <div>
                <div>
                    <input type="email" name="email" placeholder="Your Email" autofocus="">
                </div>
            </div>

            <div>
                <div>
                    <input type="password" name="password" placeholder="Your Password">
                </div>
            </div>
            <div>
                <label>
                    <input type="checkbox">
                    Remember me
                </label>
            </div>
            <button>Login</button>
        </form>
    </div>
</div>
{% endblock %}

Создайте шаблон templates/signup.html:

  • nano project/templates/signup.html

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

project/templates/signup.html

{% extends "base.html" %}

{% block content %}
<div>
    <h4>Sign Up</h4>
    <div>
        <form method="POST" action="/signup">
            <div>
                <div>
                    <input type="email" name="email" placeholder="Email" autofocus="">
                </div>
            </div>

            <div>
                <div>
                    <input type="text" name="name" placeholder="Name" autofocus="">
                </div>
            </div>

            <div>
                <div>
                    <input type="password" name="password" placeholder="Password">
                </div>
            </div>

            <button>Sign Up</button>
        </form>
    </div>
</div>
{% endblock %}

Затем создайте шаблон templates/profile.html:

  • nano project/templates/profile.html

Добавьте этот код, чтобы создать простую страницу с закодированным заголовком, welcome Anthony:

project/templates/profile.html

{% extends "base.html" %}

{% block content %}
<h2>
  Welcome, Anthony!
</h2>
{% endblock %}

Позднее мы добавим код для динамического приветствия пользователя.

После добавления шаблонов мы можем обновить выражения возврата в каждом из маршрутов, чтобы вместо текста возвращались шаблоны.

Обновите файл main.py, изменив строку импорта и маршруты index и profile:

project/main.py

from flask import Blueprint, render_template
...
@main.route('/')
def index():
    return render_template('index.html')

@main.route('/profile')
def profile():
    return render_template('profile.html')

Теперь мы обновим auth.py, изменив строку импорта и маршруты login и signup:

project/auth.py

from flask import Blueprint, render_template
...
@auth.route('/login')
def login():
    return render_template('login.html')

@auth.route('/signup')
def signup():
    return render_template('signup.html')

После внесения этих изменений страница регистрации будет следующим образом при переходе в /sign-up:

Теперь вы должны видеть страницы /, /login и /profile.

Пока что мы оставим /logout отдельно, потому что эта страница не отображает шаблон.

Шаг 5 — Создание пользовательской модели

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

Модели, созданные в Flask-SQLAlchemy, представляются классами, которые преобразуются в таблицу в базе данных. Атрибуты этих классов превратятся в столбцы этих таблиц.

Давайте вместе создадим эту пользовательскую модель:

Этот код создает пользовательскую модель со столбцами id, email, password и name:

project/models.py

from . import db

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(1000))

Мы создали пользовательскую модель и теперь можем перейти к настройке базы данных.

Шаг 6 — Настройка базы данных

Как указано в разделе «Предварительные требования», мы будем использовать базу данных SQLite. Мы можем создать базу данных SQLite самостоятельно, но сейчас используем для этого Flask-SQLAlchemy. Мы уже указали путь к базе данных в файле __init__.py, так что нам нужно просто указать Flask-SQLAlchemy создать базу данных на Python REPL.

Если вы остановите приложение и откроете Python REPL, мы сможем создать базу данных, используя метод create_all для объекта db. Убедитесь, что вы все еще находитесь в виртуальной среде и в каталоге flask_auth_app.

  • from project import db, create_app
  • db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

Примечание. Если вы незнакомы с использованием интерпретатора Python, вы можете проконсультироваться с официальной документацией.

Теперь вы видите файл db.sqlite в каталоге проекта. В этой базе данных будет наша пользовательская таблица.

Шаг 7 — Настройка функции авторизации

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

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

Создайте функцию и добавьте в ее конец переадресацию. В результате после успешной регистрации пользователь будет переадресован на страницу входа.

Обновите файл auth.py, изменив строку import и реализовав signup_post:

project/auth.py

from flask import Blueprint, render_template, redirect, url_for
...
@auth.route('/signup', methods=['POST'])
def signup_post():
    # code to validate and add user to database goes here
    return redirect(url_for('auth.login'))

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

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

Продолжим обновлять файл auth.py, добавляя элементы импорта и реализуя signup_post:

auth.py

from flask import Blueprint, render_template, redirect, url_for, request
from werkzeug.security import generate_password_hash, check_password_hash
from .models import User
from . import db
...
@auth.route('/signup', methods=['POST'])
def signup_post():
    email = request.form.get('email')
    name = request.form.get('name')
    password = request.form.get('password')

    user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database

    if user: # if a user is found, we want to redirect back to signup page so user can try again
        return redirect(url_for('auth.signup'))

    # create a new user with the form data. Hash the password so the plaintext version isn't saved.
    new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))

    # add the new user to the database
    db.session.add(new_user)
    db.session.commit()

    return redirect(url_for('auth.login'))

Примечание. Хранение паролей в формате обычного текста считается плохой практикой с точки зрения безопасности. Обычно для защиты паролей нужно использовать сложный алгоритм хэширования и шифрование паролей.

Шаг 8 — Тестирование метода регистрации

У нас готов метод регистрации, и теперь мы можем создать нового пользователя. Используйте форму для создания пользователя.

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

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

Вначале мы добавим элемент flash, выводимый до возврата на страницу регистрации.

project/auth.py

from flask import Blueprint, render_template, redirect, url_for, request, flash
...
@auth.route('/signup', methods=['POST'])
def signup_post():
    ...
    if user: # if a user is found, we want to redirect back to signup page so user can try again
        flash('Email address already exists')
        return redirect(url_for('auth.signup'))

Чтобы добавить в шаблон мигающее сообщение, нужно добавить над формой этот код. Так сообщение будет выводиться непосредственно над формой.

project/templates/signup.html

...
{% with messages = get_flashed_messages() %}
{% if messages %}
    <div>
        {{ messages[0] }}. Go to <a href="{{ url_for('auth.login') }}">login page</a>.
    </div>
{% endif %}
{% endwith %}
<form method="POST" action="/signup">

Шаг 9 — Добавление метода входа

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

После успешной проверки пароля мы знаем, что учетные данные пользователя верны, и мы можем разрешить ему вход в систему, используя Flask-Login. Вызывая login_user, Flask-Login создает сеанс этого пользователя, который сохраняется все время, пока пользователь остается в системе, и позволяет пользователю просматривать защищенные страницы.

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

project/auth.py

...
@auth.route('/login', methods=['POST'])
def login_post():
    # login code goes here
    return redirect(url_for('main.profile'))

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

project/auth.py

...
@auth.route('/login', methods=['POST'])
def login_post():
    email = request.form.get('email')
    password = request.form.get('password')
    remember = True if request.form.get('remember') else False

    user = User.query.filter_by(email=email).first()

    # check if the user actually exists
    # take the user-supplied password, hash it, and compare it to the hashed password in the database
    if not user or not check_password_hash(user.password, password):
        flash('Please check your login details and try again.')
        return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page

    # if the above check passes, then we know the user has the right credentials
    return redirect(url_for('main.profile'))

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

project/templates/login.html

...
{% with messages = get_flashed_messages() %}
{% if messages %}
    <div>
        {{ messages[0] }}
    </div>
{% endif %}
{% endwith %}
<form method="POST" action="/login">

Теперь мы можем указать, что пользователь успешно выполнил вход, но пользователю пока некуда входить. На этом этапе мы используем Flask-Login для управления сеансами пользователя.

Прежде чем начать, нам потребуется несколько вещей для работы Flask-Login. Для начала добавьте UserMixin в пользовательскую модель. UserMixin добавит в модель атрибуты Flask-Login, чтобы Flask-Login мог с ней работать.

models.py

from flask_login import UserMixin
from . import db

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(1000))

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

project/__init__.py

...
from flask_login import LoginManager
...
def create_app():
    ...
    db.init_app(app)

    login_manager = LoginManager()
    login_manager.login_view = 'auth.login'
    login_manager.init_app(app)

    from .models import User

    @login_manager.user_loader
    def load_user(user_id):
        # since the user_id is just the primary key of our user table, use it in the query for the user
        return User.query.get(int(user_id))

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

project/auth.py

from flask_login import login_user
from .models import User
...
@auth.route('/login', methods=['POST'])
def login_post():
    ...
    # if the above check passes, then we know the user has the right credentials
    login_user(user, remember=remember)
    return redirect(url_for('main.profile'))

С помощью Flask-Login мы можем использовать маршрут /login. Когда все размещено правильно, вы увидите страницу профиля.

Шаг 10 — Защита страниц

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

Чтобы защитить страницу при использовании Flask-Login, мы добавим декоратор @login_requried между маршрутом и функцией. Это не даст пользователю, не выполнившему вход в систему, увидеть этот маршрут. Если пользователь не выполнил вход, он будет переадресован на страницу входа согласно конфигурации Flask-Login.

Используя маршруты с декоратором @login_required, мы можем использовать объект current_user внутри функций. Этот объект current_user представляет пользователя из базы данных, и мы можем получить доступ ко всем атрибутам этого пользователя, используя точечную нотацию. Например, current_user.email, current_user.password, current_user.name и current_user.id будут возвращать реальные значения, хранящиеся в базе данных для пользователя, который выполнил вход в систему.

Давайте используем имя текущего пользователя и отправим его в шаблон. Затем мы используем это имя и выведем его значение.

project/main.py

from flask_login import login_required, current_user
...
@main.route('/profile')
@login_required
def profile():
    return render_template('profile.html', name=current_user.name)

Затем в файле profile.html мы обновим страницу для отображения значения name:

project/templates/profile.html

...
<h2>
  Welcome, {{ name }}!
</h2>

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

В заключение мы можем обновить представление выхода из системы. Мы можем вызвать функцию logout_user в маршруте выхода. Мы используем декоратор @login_required, потому что не имеет смысла выполнять выход для пользователя, который не выполнил вход.

project/auth.py

from flask_login import login_user, logout_user, login_required
...
@auth.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('main.index'))

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

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

templates/base.html

...
<div>
    <a href="{{ url_for('main.index') }}">
        Home
    </a>
    {% if current_user.is_authenticated %}
    <a href="{{ url_for('main.profile') }}">
        Profile
    </a>
    {% endif %}
    {% if not current_user.is_authenticated %}
    <a href="{{ url_for('auth.login') }}">
        Login
    </a>
    <a href="{{ url_for('auth.signup') }}">
        Sign Up
    </a>
    {% endif %}
    {% if current_user.is_authenticated %}
    <a href="{{ url_for('auth.logout') }}">
        Logout
    </a>
    {% endif %}
</div>

Мы успешно создали приложение с аутентификацией.

Заключение

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

Того, что мы создали в этом учебном модуле, будет достаточно для небольших приложений, но если вы хотите с самого начала использовать больше функций, подумайте об использовании библиотек Flask-User или Flask-Security, которые построены на базе библиотеки Flask-Login.

Ключи для автоматической установки SkyDNS Agent в корпоративной сети SkyDNS

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

Следующие ключи могут быть использованы:

  • /login=< login > — указание логина вашего аккаунта (пример, skydns-agent-setup.exe /S /[email protected] /pass=qwerty).
  • /pass=< password > — указание пароля (пример, skydns-agent-setup.exe /S /[email protected] /pass=qwerty). Ключи /login и /pass обязательно указываются вместе. Если будет использован только один из этих ключей, то логин и пароль будут повторно запрошены при первом запуске агента через графический интерфейс.
  • /prof=< profile > — опция позволет указать какой профиль должен быть установлен на компьютере по умолчанию (пример, skydns-agent-setup.exe /S /[email protected] /pass=qwerty /prof=My profile). Если опция не используется или указано неправильно имя профиля, то будет применен профиль Основной.
  • /conn=< interface > — опция позволяет указать на каком сетевом интерфейсе должны быть прописаны DNS нашего сервиса (пример, skydns-agent-setup.exe /S /[email protected] /pass=qwerty /conn=Wi-Fi). На интефейс который защищается, будет прописан адрес DNS 127.0.0.1. Обратите внимание, что его не надо менять вручную.
  • /pall — данный ключ используется, если надо защитить все сетевые интерфейсы. Если используются оба ключа /conn и /pall, то только первый будет использован. Если не используются ни ключ /conn, ни /pall, то будет защищено сетевое соединение по умолчанию.
  • /dupd — отключение автоматической проверки на наличие новых версий агента.
  • /darun — отключение автоматической загрузки графического интерфейса агента (иконка агента не будет показываться в трее). Этот ключ не влияет на запуск системного сервиса SkyDNS агента.
  • /D=< path > — указание пути установки агента. Эта опиця должна быть последней в строке запуска инсталлятора и не должна содержать кавычек, даже если в пути встречаются пробелы. (пример, skydns-agent-setup.exe /S /[email protected] /pass=qwerty /D=c:\program files (x86)\SkyDNS Agent). Путь должен быть указан в абсолютной форме.
  • New! /nogui — данный ключ отключает установку графического интерфейса. При его использовании будут установлены все компоненты, за исключением файла dns-agent.exe. При использовании данного ключа необходимо обязательно указывать логин и пароль (/[email protected] /pass=qwerty). 

Значения ключей с пробелами не должны экранироваться кавычками (пример /prof=Мой профиль).

Beget.API. Управление сайтами. LTD Beget.

getList

Описание

Метод возвращает список сайтов. Если к сайту прилинкованы домены, то они так же будут возвращены.

Пример вызова
https://api.beget.com/api/site/getList?login=userlogin&passwd=password&output_format=json
Пример ответа
[
   {
      "id":"125",
      "path":"site.ru\/public_html",
      "domains":[
         {
            "id":"12345",
            "fqdn":"site.ru"
         }
      ]
   },
   {
      "id":"124",
      "path":"facebook.com\/public_html",
      "domains":[
 
      ]
   },
   {
      "id":"123",
      "path":"mysite\/public_html",
      "domains":[
 
      ]
   }
]

ID сайта уникален в рамках одного пользователя.

add

Описание

Метод создает новый сайт с заданным именем.

Дополнительные параметры
  • name — имя директории с сайтом (например, site.ru).
Пример вызова
// input_data приведена в не закодированном виде для наглядности
https://api.beget.com/api/site/add?login=userlogin&passwd=password&input_format=json&output_format=json&input_data={"name":"site.ru"}

// корректный пример вызова, input_data закодирован с помощью urlencode
https://api.beget.com/api/site/add?login=userlogin&passwd=password&input_format=json&output_format=json&input_data=%7B%22name%22%3A%22site.ru%22%7D
Пример ответа

Возвращается признак удачного или нет выполнения. В случае успешного ответа полный путь к директории с сайтом будет name/public_html.

delete

Описание

Метод удаляет сайт. Если к сайту были прилинкованы домены, то они будут отлинкованы от него.

Дополнительные параметры
  • id — id сайта, тип int.
Пример вызова
// input_data приведена в не закодированном виде для наглядности
https://api.beget.com/api/site/delete?login=userlogin&passwd=password&input_format=json&output_format=json&input_data={"id":10}

// корректный пример вызова, input_data закодирован с помощью urlencode
https://api.beget.com/api/site/delete?login=userlogin&passwd=password&input_format=json&output_format=json&input_data=%7B%22id%22%3A10%7D
Пример ответа

Возвращается признак удачного или нет выполнения.

linkDomain

Описание

Метод прилинковывает домен к сайту.

Дополнительные параметры
  • domain_id — id домена. Получить уникальный id домена можно функцией domain/getList; 
  • site_id — id сайта.
Пример вызова
// input_data приведена в не закодированном виде для наглядности
https://api.beget.com/api/site/linkDomain?login=userlogin&passwd=password&input_format=json&output_format=json&input_data={"domain_id":100,"site_id":10}

// корректный пример вызова, input_data закодирован с помощью urlencode
https://api.beget.com/api/site/linkDomain?login=userlogin&passwd=password&input_format=json&output_format=json&input_data=%7B%22domain_id%22%3A100%2C%22site_id%22%3A10%7D
Пример ответа

Возвращается признак удачного или нет выполнения. После выполнения операции сайт начнет открываться по доменному имени в течении 5-10 минут.

unlinkDomain

Описание

Метод отлинковывает домен от сайта.

Дополнительные параметры
  • domain_id — id домена. Получить уникальный id домена можно функцией domain/getList.
Пример вызова
// input_data приведена в не закодированном виде для наглядности
https://api.beget.com/api/site/unlinkDomain?login=userlogin&passwd=password&input_format=json&output_format=json&input_data={"domain_id":100}

// корректный пример вызова, input_data закодирован с помощью urlencode
https://api.beget.com/api/site/unlinkDomain?login=userlogin&passwd=password&input_format=json&output_format=json&input_data=%7B%22domain_id%22%3A100%7D
Пример ответа

Возвращается признак удачного или нет выполнения.

freeze

Описание

Метод запрещает изменение файлов сайта.

Дополнительные параметры
  • id — id сайта. Получить уникальный id сайта можно функцией site/getList;
  • excludedPaths — список путей, в которых будет разрешено изменение файлов.
Пример вызова
// input_data приведена в не закодированном виде для наглядности
https://api.beget.com/api/site/freeze?login=userlogin&passwd=password&input_format=json&output_format=json&input_data={"id": 100, "excludedPaths": ["tmp", "cache"]}

// корректный пример вызова, input_data закодирован с помощью urlencode
https://api.beget.com/api/site/freeze?login=userlogin&passwd=password&input_format=json&output_format=json&input_data=%7B%22id%22%3A+100%2C+%22excludedPaths%22%3A+%5B%22tmp%22%2C+%22cache%22%5D%7D
Пример ответа

Возвращается признак удачного или нет выполнения. Задание помещается в очередь и выполняется в течении 5-10 минут в зависимости от размера сайта.

unfreeze

Описание

Метод разрешает изменение файлов сайта.

Дополнительные параметры
  • id — id сайта. Получить уникальный id сайта можно функцией site/getList.
Пример вызова
// input_data приведена в не закодированном виде для наглядности
https://api.beget.com/api/site/unfreeze?login=userlogin&passwd=password&input_format=json&output_format=json&input_data={"id": 100}

// корректный пример вызова, input_data закодирован с помощью urlencode
https://api.beget.com/api/site/unfreeze?login=userlogin&passwd=password&input_format=json&output_format=json&input_data=%7b%22id%22%3a+100%7d
Пример ответа

Возвращается признак удачного или нет выполнения. Задание помещается в очередь и выполняется в течении 5-10 минут в зависимости от размера сайта.

isSiteFrozen

Описание

Метод возвращает текущий статус сайта — доступно ли редактирование файлов.

Дополнительные параметры
  • site_id — id сайта. Получить уникальный id сайта можно функцией site/getList.
Пример вызова
// input_data приведена в не закодированном виде для наглядности
https://api.beget.com/api/site/isSiteFrozen?login=userlogin&passwd=password&input_format=json&output_format=json&input_data={"site_id": 100}

// корректный пример вызова, input_data закодирован с помощью urlencode
https://api.beget.com/api/site/isSiteFrozen?login=userlogin&passwd=password&input_format=json&output_format=json&input_data=%7B%22site_id%22%3A+100%7D
Пример ответа
"status": "success",
"answer": {
		"status": "success",
		"result": true
}

Flask-Login — документация Flask-Login 0.4.1

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

Будет:

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

Однако это не так:

  • Навязать вам конкретную базу данных или другой метод хранения. Ты полностью отвечает за загрузку пользователя.
  • Запрещает вам использовать имена пользователей и пароли, идентификаторы OpenID или любой другой метод. аутентификации.
  • Обработка разрешений, выходящих за рамки «авторизован или нет».”
  • Обработка регистрации пользователя или восстановления учетной записи.

Установка

Установите расширение с pip:

 $ pip install flask-login
 

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

Наиболее важной частью приложения, использующего Flask-Login, является LoginManager класс. Вы должны создать его для своего приложения где-нибудь в ваш код, например:

 login_manager = LoginManager ()
 

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

После создания фактического объекта приложения вы можете настроить его для войти с помощью:

 login_manager.init_app (приложение)
 

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

Предупреждение: УБЕДИТЕСЬ, что используете данную команду в Раздел «Как сгенерировать хорошие секретные ключи», чтобы сгенерировать свой собственный секретный ключ.НЕ ИСПОЛЬЗУЙТЕ первый пример.

Как это работает

Вам нужно будет предоставить обратный вызов user_loader . Этот обратный вызов используется для перезагрузки объекта пользователя из идентификатора пользователя, хранящегося в сеансе. Это должен взять unicode ID пользователя и вернуть соответствующего пользователя объект. Например:

 @ login_manager.user_loader
def load_user (user_id):
    вернуть User.get (user_id)
 

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

Ваш пользовательский класс

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

is_authenticated
Это свойство должно возвращать True , если пользователь аутентифицирован, т.е. они предоставили действительные учетные данные. (Только авторизованные пользователи будут выполнять критерии login_required .)
активный
Это свойство должно возвращать True , если это активный пользователь — вдобавок для аутентификации, они также активировали свою учетную запись, а не были приостановлено, или любое условие вашего приложения для отклонения учетной записи. Неактивные учетные записи не могут войти в систему (конечно, без принуждения).
is_anonymous
Это свойство должно вернуть True , если это анонимный пользователь. (Действительный вместо этого пользователи должны возвращать False .)
get_id ()
Этот метод должен возвращать unicode , который однозначно идентифицирует этого пользователя, и может использоваться для загрузки пользователя из user_loader Перезвоните. Обратите внимание, что этот должен быть юникодом — если идентификатор изначально int или какой-либо другой тип, вам нужно будет преобразовать его в unicode .

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

Пример входа в систему

После аутентификации пользователя вы входите в систему с помощью login_user функция.

Например:

 @ app.route ('/ login', methods = ['GET', 'POST'])
def login ():
    # Здесь мы используем какой-то класс для представления и проверки наших
    # данные клиентской формы. Например, WTForms - это библиотека, которая будет
    # обрабатываем это за нас, и мы используем настраиваемую LoginForm для проверки.
    form = LoginForm ()
    если форма.validate_on_submit ():
        # Войдите и подтвердите права пользователя.
        # пользователь должен быть экземпляром вашего класса `User`
        login_user (пользователь)

        flask.flash ('Успешный вход в систему.')

        next = flask.request.args.get ('следующий')
        # is_safe_url должен проверять, безопасен ли URL для перенаправления.
        # См. Пример на http://flask.pocoo.org/snippets/62/.
        если не is_safe_url (далее):
            вернуть flask.abort (400)

        вернуть flask.redirect (next или flask.url_for ('index'))
    возвратная колба.render_template ('login.html', форма = форма)
 

Предупреждение: Вы ДОЛЖНЫ проверить значение следующего параметра . Если вы этого не сделаете, ваше приложение будет уязвимо для открытых перенаправлений. Для примера реализация is_safe_url см. этот фрагмент Flask.

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

 {% если current_user.is_authenticated%}
  Привет, {{current_user.имя }}!
{% endif%}
 

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

 @ app.route ("/ настройки")
@login_required
def settings ():
    проходить
 

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

 @ app.route ("/ logout")
@login_required
def logout ():
    logout_user ()
    вернуть перенаправление (где-то)
 

Они выйдут из системы, и все файлы cookie для их сеанса будут удалены.

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

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

Имя журнала в представлении может быть установлено как LoginManager.login_view . Например:

 login_manager.login_view = "users.login"
 

По умолчанию отображается сообщение Пожалуйста, войдите в систему, чтобы получить доступ к этой странице. Кому настроить сообщение, установить LoginManager.login_message :

 login_manager.login_message = u "Bonvolu Ensaluti por uzi tiun paĝon."
 

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

 login_manager.login_message_category = "информация"
 

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

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

 @ login_manager.unauthorized_handler
def unauthorized ():
    # делать что-нибудь
    вернуть a_response
 

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

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

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

 @ login_manager.request_loader
def load_user_from_request (запрос):

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

    # затем попробуйте войти в систему, используя базовую аутентификацию
    api_key = request.headers.get ('Авторизация')
    если api_key:
        api_key = api_key.replace ('Базовый', '', 1)
        пытаться:
            api_key = base64.b64decode (api_key)
        кроме TypeError:
            проходить
        user = User.query.filter_by (api_key = api_key) .first ()
        если пользователь:
            возвратный пользователь

    # наконец, вернуть None, если оба метода не вошли в систему пользователя
    return None
 

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

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

  • is_active и is_authenticated являются False
  • is_anonymous is True
  • get_id () возвращает Нет

Если у вас есть особые требования для анонимных пользователей (например, им нужно чтобы иметь поле разрешений), вы можете предоставить вызываемый объект (либо класс, либо factory), который создает анонимных пользователей для LoginManager с:

 login_manager.anonymous_user = MyAnonymousUser
 

Помни меня

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

Функцию

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

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

Альтернативные жетоны

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

 @ login_manager.user_loader
def load_user (user_id):
    вернуть User.query.filter_by (альтернативный_ид = идентификатор_пользователя) .first ()
 

Тогда метод get_id вашего класса User вернет альтернативный идентификатор вместо основного идентификатора пользователя:

 def get_id (сам):
    вернуть unicode (self.alternative_id)
 

Таким образом, вы можете изменить альтернативный идентификатор пользователя на новый случайным образом генерируемое значение, когда пользователь меняет свой пароль, что обеспечит их старые сеансы аутентификации перестанут быть действительными. Обратите внимание, что альтернатива id по-прежнему должен однозначно идентифицировать пользователя … думайте об этом как о втором идентификаторе пользователя.

Свежие логины

Когда пользователь входит в систему, его сеанс помечается как «свежий», что означает, что они действительно аутентифицировались на этом сеансе. Когда их сеанс уничтожен и они снова вошли в систему с помощью файла cookie «запомнить меня», он помечен как «Несвежий». login_required не различает свежесть, которая подходит для большинства страниц. Однако такие деликатные действия, как изменение чьего-то личная информация должна требовать нового входа в систему. (Действия вроде изменения пароль всегда должен требовать повторного ввода пароля, независимо от того.)

fresh_login_required , в дополнение к проверке того, что пользователь вошел в систему in, также гарантирует, что их логин будет свежим. Если нет, он отправит их на страница, на которой они могут повторно ввести свои учетные данные. Вы можете настроить его поведение так же, как вы можете настроить login_required , установив LoginManager.refresh_view , needs_refresh_message и needs_refresh_message_category :

 login_manager.refresh_view = "учетные записи.повторно аутентифицировать "
login_manager.needs_refresh_message = (
    u «Чтобы защитить свою учетную запись, повторно авторизуйтесь для доступа к этой странице».
)
login_manager.needs_refresh_message_category = "информация"
 

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

 @ login_manager.needs_refresh_handler
def refresh ():
    # делать что-нибудь
    вернуть a_response
 

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

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

Детали файла cookie можно настроить в настройках приложения.

REMEMBER_COOKIE_NAME Имя файла cookie для хранения «запомнить меня». информация в формате. По умолчанию: Remember_token
REMEMBER_COOKIE_DURATION Количество времени до истечения срока действия cookie, как объект datetime.timedelta или целые секунды. По умолчанию: 365 дней (1 невисокосный год по григорианскому календарю)
REMEMBER_COOKIE_DOMAIN Если cookie «Запомнить меня» должен пересекать домены, установите здесь значение домена (т.е.е. .example.com позволит использовать cookie на всех поддомены example.com ). По умолчанию: Нет
REMEMBER_COOKIE_PATH Ограничивает cookie «Запомнить меня» определенным путем. По умолчанию: /
REMEMBER_COOKIE_SECURE Ограничивает область действия cookie «Запомнить меня» до защищенные каналы (обычно HTTPS). По умолчанию: Нет
REMEMBER_COOKIE_HTTPONLY Предотвращает сохранение файла cookie «Запомнить меня». доступ осуществляется клиентскими скриптами. По умолчанию: Ложь
REMEMBER_COOKIE_REFRESH_EACH_REQUEST Если установлено значение True , cookie обновляется каждый раз. запрос, который увеличивает время жизни. Работает как Flask’s SESSION_REFRESH_EACH_REQUEST . По умолчанию: Ложь

Защита сеанса

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

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

 login_manager.session_protection = "сильный"
 

Или, чтобы отключить:

 login_manager.session_protection = Нет
 

По умолчанию активирован в «базовом» режиме . Его можно отключить в конфигурации приложения, задав для параметра SESSION_PROTECTION значение None , «базовый» , или «сильный» .

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

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

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

Отключение cookie сеанса для API

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

 из колбы импортной г
из flask.sessions import SecureCookieSessionInterface
из flask_login импорт user_loaded_from_header

класс CustomSessionInterface (SecureCookieSessionInterface):
    "" "Запретить создание сеанса из запросов API."" "
    def save_session (self, * args, ** kwargs):
        если g.get ('login_via_header'):
            возвращение
        вернуть super (CustomSessionInterface, self) .save_session (* args,
                                                                ** kwargs)

app.session_interface = CustomSessionInterface ()

@ user_loaded_from_header.connect
def user_loaded_from_header (self, user = None):
    g.login_via_header = Верно
 

Это предотвращает установку файла cookie сеанса Flask всякий раз, когда пользователь аутентифицируется. используя ваш header_loader .

Локализация

По умолчанию LoginManager использует flash для отображения сообщений, когда пользователь требуется для входа в систему. Эти сообщения на английском языке. Если вам нужно локализации, установите для атрибута localize_callback LoginManager значение функция, которая будет вызываться с этими сообщениями перед их отправкой на flash , например получить текст . Эта функция будет вызываться с сообщением и его возвратом. вместо этого значение будет отправлено на flash .

Документация по API

Эта документация автоматически создается из исходного кода Flask-Login.

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

класс flask_login. LoginManager ( app = None , add_context_processor = True ) [источник]

Этот объект используется для хранения настроек, используемых для входа в систему. Экземпляры из LoginManager — это , а не , привязанные к определенным приложениям, поэтому вы можете создайте его в основной части вашего кода, а затем привяжите его к своему app в заводской функции.

setup_app ( app , add_context_processor = True ) [источник]

Этот метод устарел. Пожалуйста, используйте LoginManager.init_app () вместо .

несанкционированный () [источник]

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

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

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

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

needs_refresh () [источник]

Это вызывается, когда пользователь вошел в систему, но он должен быть повторная аутентификация, потому что их сеанс устарел.Если вы зарегистрируете обратный вызов с needs_refresh_handler , тогда он будет вызван. В противном случае он выполнит следующие действия:

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

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

Общая конфигурация

user_loader ( обратный вызов ) [источник]

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

Параметры: обратный вызов ( вызываемый ) — обратный вызов для получения объекта пользователя.

Эта функция устарела. Пожалуйста, используйте LoginManager.request_loader () вместо этого.

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

Параметры: обратный вызов ( вызываемый ) — обратный вызов для получения объекта пользователя.
анонимный_пользователь

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

неавторизованный Конфигурация

login_view

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

сообщение_входа

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

unauthorized_handler ( callback ) [источник]

Это установит обратный вызов для неавторизованного метода , который среди остальное используется login_required .Это не требует аргументов, и должен возвращать ответ, который будет отправлен пользователю вместо его нормальный вид.

Параметры: callback ( callable ) — обратный вызов для неавторизованных пользователей.

needs_refresh Конфигурация

обновить_просмотр

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

needs_refresh_message

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

needs_refresh_handler ( callback ) [источник]

Это установит обратный вызов для метода needs_refresh , который среди остальное используется fresh_login_required . Не требует аргументов, и должен возвращать ответ, который будет отправлен пользователю вместо его нормальный вид.

Параметры: callback ( callable ) — обратный вызов для неавторизованных пользователей.

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

flask_login. текущий_пользователь

Прокси для текущего пользователя.

flask_login. login_fresh () [источник]

Возвращает True , если текущий логин свежий.

flask_login. login_user ( user , Remember = False , duration = None , force = False , fresh = True ) [источник]

Выполняет вход пользователя в систему. Вы должны передать ему фактический объект пользователя. Если Свойство пользователя is_active Ложь , они не войдут в систему если только force не True .

Это вернет True , если попытка входа будет успешной, и False , если это не удается (т.е. потому что пользователь неактивен).

Параметры:
  • пользователь ( объект ) — Пользовательский объект для входа в систему.
  • запомнить ( bool ) — следует ли помнить пользователя после истечения его сеанса. По умолчанию Ложь .
  • длительность ( datetime.timedelta ) — время до истечения срока действия запоминающего файла cookie. Если Нет используется значение, заданное в настройках.По умолчанию Нет .
  • force ( bool ) — если пользователь неактивен, установка этого значения на True будет регистрировать их в любом случае. По умолчанию Ложь .
  • свежий ( bool ) — установка этого значения на Ложь будет входить в систему пользователя с сеансом отмечен как не «свежий». По умолчанию True .
flask_login. logout_user () [источник]

Выполняет выход пользователя из системы.(Вам не нужно передавать фактического пользователя.) Это будет также очистите файл cookie «запомнить меня», если он существует.

flask_login. confirm_login () [источник]

Устанавливает текущий сеанс как свежий. Сессии устаревают, когда они перезагружаются из файла cookie.

Защита взглядов

flask_login. login_required ( func ) [источник]

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

 @ app.route ('/ сообщение')
@login_required
def post ():
    проходить
 

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

, если не current_user.is_authenticated:
    вернуть current_app.login_manager.unauthorized ()
 

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

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

Параметры: func ( function ) — Функция просмотра для украшения.
flask_login. fresh_login_required ( func ) [источник]

Если вы украсите вид этим, это гарантирует, что текущий пользователь логин свежий — i.е. их сеанс не был восстановлен из «запомни меня» куки. Конфиденциальные операции, такие как изменение пароля или электронной почты, должны быть защищенным этим, чтобы препятствовать усилиям похитителей файлов cookie.

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

Действует идентично декоратору login_required () в отношении к переменным конфигурации.

Параметры: func ( function ) — Функция просмотра для украшения.

Помощники объекта пользователя

класс flask_login. UserMixin [источник]

Это обеспечивает реализации по умолчанию для методов, которые Flask-Login ожидает, что у пользовательских объектов будет.

класс flask_login. AnonymousUserMixin [источник]

Это объект по умолчанию для представления анонимного пользователя.

Утилиты

flask_login. login_url ( login_view , next_url = None , next_field = ‘next’ ) [источник]

Создает URL-адрес для перенаправления на страницу входа. Если только login_view при условии, это просто вернет для него URL.Если указан next_url , однако при этом к строке запроса будет добавлен параметр next = URL . так что представление входа может перенаправить обратно на этот URL. Flask-Login по умолчанию неавторизованный обработчик использует эту функцию при перенаправлении на ваш URL-адрес для входа. Чтобы принудительно использовать имя хоста, установите для хоста FORCE_HOST_FOR_REDIRECTS . Этот предотвращает перенаправление на внешние сайты, если заголовки запроса Host или X-Forwarded-For присутствует.

Параметры:
  • login_view ( str ) — имя представления входа.(В качестве альтернативы фактическое URL-адрес для входа в систему.)
  • next_url ( str ) — URL-адрес для представления входа в систему для перенаправления.
  • next_field ( str ) — В каком поле сохранить следующий URL-адрес (по умолчанию следующий .)

Сигналы

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

flask_login. user_logged_in

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

flask_login. user_logged_out

Отправляется, когда пользователь выходит из системы. В дополнение к приложению (которое является отправитель), ему передается пользователя , который является пользователем, выходящим из системы.

flask_login. user_login_confirmed

Отправляется после подтверждения входа пользователя с пометкой как новый. (Нет потребовал нормального входа в систему.) Он не получает никаких дополнительных аргументов, кроме приложения.

flask_login. user_unauthorized

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

flask_login. user_needs_refresh

Отправляется, когда в LoginManager вызывается метод needs_refresh . Это не получает никаких дополнительных аргументов, кроме приложения.

flask_login. session_protected

Отправляется всякий раз, когда срабатывает защита сеанса, и сеанс либо помечены как несвежие или удаленные. Никаких дополнительных аргументов кроме приложение.

логин в предложении | Примеры предложений по Кембриджскому словарю

Эти примеры взяты из корпусов и из источников в Интернете.Любые мнения в примерах не отражают мнение редакторов Cambridge Dictionary, Cambridge University Press или его лицензиаров.

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

Из

Википедия