Васильев Андрей Михайлович, 2022
Версии презентации
Авторизовать необходимо любое действие, которое пользователь может выполнить с приложением:
То есть необходимо проверять возможность выполнения любой ПРУД-операции
Как и в случае с аутентификацией, авторизация должна происходить при каждом отдельном запросе от клиента к серверу
Потенциально можно реализовать две стратегии в организации интерфейса
Для узкоспециализированных систем со сложными подходами к авторизации можно использовать первый подход, но для большинства пользовательских систем следует использовать второй подход
Права доступа всегда относятся к конкретному субъекту, но существует несколько подходов к установлению связи между субъектом и правами
Можно выделить следующие общие подходы предоставления прав доступа:
В рамках приложения выделяются действия, требующие авторизацию
Затем выполняется выдача прав одним из возможных способов:
В рамках приложения выделяется концепция «роли», которая может выполнять разумный связный набор действий внутри предметной области приложения
Использование роли является логичным продолжением использования сценариев использования и пользовательских историй для описания функциональности приложения
Каждому пользователю системы назначается роль
Данная схема похожа на схему выдачи прав ролям, однако она более сложная:
Права в системе могут быть прописаны либо статически, либо динамически
Для систем небольшого размера достаточно статического определения прав доступа. Для систем среднего и большего размера необходимо использовать системы динамического распределения прав
Ввиду востребованности и требований обеспечения безопасности системы задачу по выделению прав выносят в отдельную систему с которой взаимодействуют по ряду протоколов: SAML, OpenID Connect и т.д.
Протокол OpenID Connect является расширением протокола OAuth 2.0, предоставляющий слой для идентификации пользователя после авторизации на идентификации провайдера
Протокол поддерживает следующие потоки авторизации:
Рассмотрим первые два потока, предназначенные для пользовательских приложений
В неявном потоке авторизации у пользователя нет возможности скрыть какие-то данные, так как состояние веб-приложения всегда можно исследовать средствами разработки
sequenceDiagram participant client as Клиент participant provider as Провайдер идентификации client ->> provider: Запрос на аутентификацию с передачей идентификатора клиента provider ->> client: Показывает интерфейс для аутентификации client ->> provider: Выполняет аутентификацию и формирует JWT-токен provider ->> client: Высылает JWT-токен с данными аутентификации и авторизации client ->> client: Проверяет JWT-токен
В рамках данного потока взаимодействие провайдера идентификации включает взаимодействие с серверным приложением
sequenceDiagram participant client as Клиент participant provider as Провайдер идентификации participant server as Сервер participant token as Служба токенов participant user as Служба информации client ->> provider : Запрос на аутентификацию с передачей идентификатора клиента provider ->> client : Показ страницы аутентификации client ->> provider : Отправка запроса на авторизацию provider ->> server : Передача кода для получения токенов server ->> token: Получение токенов доступа и JWT-токена server ->> user: Получение дополнительной информации о пользователе server ->> client: Показ авторизованных данных
Стоит учитывать, что авторизация возможна только после авторизации
Поток идентификации и аутентификации в веб-приложении
sequenceDiagram participant client as Клиент participant server as Веб-приложение server ->> client : Форма входа в приложение client ->> server : Корректные данные пользователя server ->> server : Создание сессионного токена server ->> client : Передача сессионного токена в куках
Сессионный токен удобно оформить в виде JWT-токена, чтобы уменьшить объём данных, которые надо сохранять на сервере для выполнения авторизации
В рамках учебных приложений будем использовать подход с определением ролей
Для распределения ролей будет достаточным отредактировать хранилище напрямую
При выполнении действий и при показе пользовательского интерфейса необходимо проверить разрешения для текущего аутентифицированного пользователя
При использовании второго подхода можно логику по вычислению списка разрешений делегировать фильтру и сохранять их в контекст обработчика
flowchart LR request["Запрос"] user["Фильтр аутентификации"] auth["Фильтр авторизации"] handler["Обработчик запроса"] request --> user --> auth --> handler
Внутри приложения для реализации ролей можно использовать следующий подход:
data class RolePermissions(
val listEntries: Boolean,
val showEntry: Boolean,
val addEntry: Boolean,
val editEntry: Boolean,
val deleteEntry: Boolean,
)
val AnonymousRole = RolePermissions(
listEntries = true,
showEntry = true,
addEntry = false,
editEntry = false,
deleteEntry = false,
)
val GenericUser = AnonymousRole.copy(
addEntry = true,
)
val Administrator = GenericUser.copy(
editEntry = true,
deleteEntry = true,
)
Представленная схема обеспечивает доступ ко всем функциям «по умолчанию», то есть обычный пользователь не может удалять или редактировать записи
Значимым исключением из данной практики является фактор владения объектом. Если пользователь является владельцем, то он может выполнять расширенный набор действий
Для определения права владения:
Проверку на владение можно проводить исключительно на уровне обработчика
sequenceDiagram participant client as Клиент participant server as Веб-приложение client ->> server : GET-запрос на редактирование alt Пользователь авторизован на выполнение действий server ->> client : HTML-документ с формой, заполненной данными else server ->> client : Ответ с кодом 403, доступ запрещён end client ->> client : Заполнение формы client ->> server : POST-запрос (PUT) с данными формы alt Данные формы верны server ->> client : Перенаправление на страницу ресурса else server ->> client : Отображение формы с данными и с сообщением об ошибке end opt Пользователь не авторизован server ->> client : Ответ с кодом 403, доступ запрещён end
sequenceDiagram participant client as Клиент participant server as Веб-приложение client ->> server : GET-запрос на удаление элемента alt Пользователь авторизован на выполнение действия server ->> client : HTML-документ с формой подтверждения удаления else server ->> client : Ответ с кодом 403, доступ запрещён end client ->> server : POST-запрос (DELETE) alt Пользователь авторизован на выполнение действия server ->> client : Перенаправление на страницу списка else server ->> client : Ответ с кодом 403, доступ запрещён end