Пишем web на Python3, ограничиваем доступ к сервису

newbie

Опубликован:  2019-03-21T07:01:00.698043Z
Отредактирован:  2019-04-03T06:09:19.991489Z

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

В соответствии с начальным замыслом пользователи группы "Изгнанные" не могут авторизоваться на сайте. В предыдущем выпуске блога я создал пользователя scain и определил его в эту группу.

xOzW2kZrtA.png

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

kq3FpXxDlj.png

cIK9gQBCmw.png

Оставляю браузер в покое на некоторое время с активной сессией scain, иду в PyCharm и открываю файл с функциями представления из каталога selfish/auth. На текущий момент этот файл выглядит так.

QmVEgTwOGj.png

Целевая функция make_before_request отвечает за действия, которые выполняются перед каждым запросом текущего пользователя. Чтобы ограничить scain-а, мне достаточно переписать эту функцию.

...
from ..models.auth_units import permissions

...


@auth.before_app_request
def make_before_request():
    if current_user.is_authenticated:
        current_user.ping()
        if current_user.can(permissions.CANNOT_LOG_IN):
            logout_user()
            flash('Ваше присутствие в сервисе нежелательно.')
            return redirect(url_for('auth.login'))

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

z9e22dudAN.png

Обновляю страницу в браузере.

tUbtpbsAAg.png

eVoDHC2rI0.png

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

Перейдём ко второй части марлезонского балета. Пользователи из группы "Читатели", у меня уже есть один представитель этой группы - fossman.

pUnXLrNhhw.png

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

Создаю новую подпрограмму, для этого мне нужен каталог и два файла в нём.

mkdir selfish/admin
touch selfish/admin/__init__.py
touch selfish/admin/views.py

В файле selfish/admin/__init__.py создаю новый экземпляр класса Blueprint.

from flask import Blueprint

admin = Blueprint('admin', __name__)

from . import views

Открываю файл selfish/__init__.py и регистрирую новую подпрограмму в теле функции create_app.

RMWyoevmWm.png

Открываю файл selfish/admin/views.py и создаю в нём функцию представления для страницы, на которой впоследствии будут фильтроваться и отображаться все зарегистрированные пользователи сервиса. Доступ к этой странице закрываю разрешением FOLLOW_USERS при помощи разработанного в предыдущем выпуске блога декоратора.

from flask import render_template
from flask_login import login_required

from ..deco import permission_required
from ..models.auth_units import permissions
from . import admin


@admin.route('/society')
@login_required
@permission_required(permissions.FOLLOW_USERS)
def show_users():
    return render_template('admin/society.html')

Здесь я создал новую функцию представления, дал ей уникальный url-адрес и декорировал двумя дополнительными декораторами, ограничивающими доступ к этой странице приложения. Логика декораторов исполняется сверху вниз перед исполнением логики самой функции представления. Таким образом соответствующая страница будет требовать входа в сервис у анонимных пользователей и транслировать HTTP-ошибку 403 всем авторизованным и не имеющим разрешения FOLLOW_USERS пользователям. На текущий момент сама функция представления не делает ничего, кроме интерпретации заданного шаблона, оригинальная логика в ней появится чуть позже на следующих этапах разработки. Создаю шаблон для этой функции представления.

mkdir selfish/templates/admin
touch selfish/templates/admin/society.html

Открываю шаблон в редакторе и пишу в него следующий код.

Bun0l46K7k.png

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

Чтобы облегчить доступ к этой странице авторизованным пользователям, я добавлю в главное меню selfish соответствующую ссылку, для этого открываю файл базового шаблона, нахожу в нём следующий тег <ul class="nav navbar-nav">, на данный момент он выглядит так.

dHVWVMB7Wz.png

Редактирую этот тег и привожу его к следующему виду.

<ul class="nav navbar-nav">
    <li><a href="">События</a></li>
    {% if current_user.can(permissions.FOLLOW_USERS) %}
        <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
            Генштаб <b class="caret"></b>
            </a>
            <ul class="dropdown-menu">
                <li>
                    <a href="{{ url_for('admin.show_users') }}">
                        Сообщество
                    </a>
                </li>
            </ul>
        </li>
    {% endif %}
</ul>

Запускаю отладочный сервер и вновь отправляюсь в браузер. У меня есть два пользователя: newbie и fossman. Разрешения этих пользователей отличаются кардинально. Вхожу сначала пользователем newbie.

bw04fbCszv.png

Отмечаю, что в главном меню появилась новая ссылка, пытаюсь по ней перейти.

syiNSrQDXo.png

Оказываюсь на новой странице, где указан мой псевдоним и группа.

WS3nncHlax.png

Выхожу при помощи ссылок главного меню приложения.

6YBMuyzKyR.png

Пробую снова войти, но на этот раз как fossman.

9sTK5JDMjK.png

И замечаю удивительную метаморфозу - fossman не имеет в своём распоряжении нового раздела главного меню - "Генштаб".

xgos6HNhZ1.png

Отлично... А как насчёт ручного ввода url-адреса страницы с ограниченным доступом в адресную строку браузера? Ввожу.

Xekjoc7QpB.png

Ку-ку, Гриня... Пользователь из группы "Читатели" не имеет доступа к этой странице. Цель достигнута.

Подытожим наши достижения на текущий момент:

  • у приложения появилась система разрешений пользователей, на основе которой можно достаточно просто ограничить отдельным пользователям доступ к тем или иным функциональным возможностям сервиса;
  • у приложения появилась новая подпрограмма admin, что прекрасно демонстрирует расширяемость selfish.

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

Комментарии: