modules-monorepo
v0.2.3
Published
Authentication and authorization related modules.
Downloads
5
Readme
Модуль авторизации
Общие сведения.
Репозиторий содержит 4 пакета:
@libs/security - библиотека для работы с jwt и csrf токенами.
@skeleton/common - пакет для общего функционала, используемого в других skeleton-модулях. (планируется в будущем вынести в отдельный репозиторий)
@skeleton/auth - framework agnostic модуль авторизации (подключается к express, как middleware).
@skeleton/auth-nest - модуль для nestjs, оборачивающий функционал @skeleton/auth.
demo-auth и demo-auth-nest - тестовые с подключенными модулями авторизации (на чистом экспресс и на nestjs соотвественно)
Порядок развёртывания репозитория.
- Для комфортной работы с репозиторием установите глобально пакеты @nestjs/cli и ts-node.
- Склонируйте репозиторий.
- Из корня репозитория выполняем последовательно:
npm install
npm run bootsrap #поздаёт симлинки между пакетами, т. к. они зависят друга)
npm run build
В папках demo-auth и demo-auth-nest создайте копии .example.env c названием .env
В случае, если у вас локально установлен REDIS в файлах .env установите параметры подключения (SESS_REDIS_*) к нему. Если не установлен - два варианта: а) поставьте :-) б) разверните редис в контейнере (см. скрипты в sess_redis);
Для проверки корректности развёртывания выполните:
npm run test # из корня проекта.
Если все тесты пройдены.. отлично )
- Для запуска сервисов с модулем авторизации, требуется поднятый сервер аутентификации (тесты поднимают его автоматически). Чтобы просто запустить сервис для отладки, можно поднять моковый сервер аутентификации:
npm run tools:mock-server
# Сервис ищёт файл api-mock.config.js, в котором указано, что и в каких случаях надо возвращать.
Публикация пакетов.
Подготовка.
Для работы с пакетами @skeleton/* и @libs/* (как для скачивания, так и для публикации) необходимо настроить npm:
npm config set @skeleton:registry http://host:port
npm config set @libs:registry http://host:port
npm login --registry http://host:port
На сегодняшний день в качестве registry используется: http://nexus.infra.medpoint24.lo/repository/medpoint24_npm/
Публикация.
Изначально для публикации пакетов использовалась lerna (команда npm run pub из корня репозитория). Но лерна при публикации делает некоторые не совсем очевидные вещи (добавляет теги, делает git push и т. п.), что не всегда удобно.
Поэтому на данный момент пакеты публикуются при помощи
npm publish # из папки пакета
Стремимся к CI. То есть публикация пакетов будет происходить при пуше в мастер.
API
Оба demo-сервиса имеют идентичное api:
GET /user (требуется разрешение: 'VIEW_USER')
POST /user (требуется разрешение: 'CREATE_USER')
DELETE /user (требуются разрешения: 'DELETE_USER' И 'VIEW_USER')
POST /drop/db (требуются разрешения: 'ADMIN' ИЛИ 'SUPERADMIN')
GET /ignored (разрешения не требуется, как и авторизация вообще)
Все методы не требует параметров и при успешной авторизации возвращают 200 true.
Описание системы.
Авторизация пользователя проходит в два этапа:
- Валидация jwt и csrf токенов (на каждый запрос).
- Проверка прав доступа (права устанавливаются на каждый роут отдельно).
Порядок действий следующий:
- Для получения доступа клиент должен в заголовке Authorization приложить jwt-токен, полученный у сервера аутентификации. Authorization: Bearer df3gf....
# Для создания тестового токена можно воспользоваться утилитой:
npm run tools:jwt
# Выведет валидный токен в консоль.
Модуль авторизации хэширует токен и по хэшу пытается найти сохранённые данные в REDIS. Если на сервис уже приходили с данным токеном, расшиврованные данные из него, а также права пользователя уже хранятся в REDIS. Если нет - запускается полная процедура (см. ниже)
В случае, если сессия в REDIS не найдена, jwt-токен валидируется и расшифровывается. Затем отправляется запрос на сервер аутентификации для получения прав. Права (permissions) пользователя представляют из себя массив строк вида: ['CREATE_USER', 'UPDATE_USER']. Полученные права используются для получения доступа к конкретному роуту.
ВАЖНО! При успешной авторизации, в каждом ответе модуль прикладывает csrf-токен (в заголовке X-Csrf-Token). Его необходимо приложить в таком же заголовке к следующему запросу. ПЕРЕГЕНЕРИРУЕТСЯ ПРИ КАЖДОМ ЗАПРОСЕ
Если сессия в REDIS найдена, проверяется не истёк ли срок действия токена, а также валидируется csrf-токен. Если всё ОК, пропускаем дальше на этап проверки прав доступа.
Права доступа устанавливаются на каждый роут отдельно. Если указывается несколько, то по умолчанию будет проверяться наличие ВСЕХ (это можно изменить дополнительным параметром) - см. demo-сервисы.
В случае неудачной попытки доступа клиенту возвращаются код ошибки.
Дополнительные параметры
Настройки модуля авторизации берутся из .env файлов. За что отвечают конкретные значения - написано в комментариях.
Следуюет отметить следующии возможности:
- Для печати в консоль всех логов модуля авторизации установите LOG_LEVEL=verbose
- Чтобы клиенту кроме кода ошибки возвращалось также описание, установите VERBOSE_ERRORS=true
- Для роутов перечисленных через запятую в параметре IGNORE_ROUTES авторизация будет полностью пропущена. ВАЖНО! Если указать '/public', будут открыты все роуты, содержащие данную подстроку.
- Авторизация может быть полностью отключена (в тестовых целях) путём установки параметра DISABLE_AUTH=true В этом случае, каждый запрос получит разрешения перечисленные через запятую в параметре TEST_PERMISSIONS
- Все запросы с ошибками 401 и 403 будут возвращаться клиенту с задержкой указанной в параметре AUTH_ERRORS_DELAY (в миллисекундах)
Сценарии:
Incorrect Jwt.
STATE: any
✓ should return 401 if JWT is missing.
✓ should return 401 if JWT signature is incorrect.
1) should return 401 if JWT is expired
✓ should return 401 if JWT payload can`t be parsed (109ms)
Correct Jwt.
STATE: no session.
X-Csrf-Token header exists.
✓ should return 401 if Csrf token EXISTS. (125ms)
X-Csrf-Token header NOT exists.
State: auth-server UNREACHABLE
✓ should return 500
STATE: auth-server returns 401
✓ should return 401
STATE: auth-server provides SUFFICIENT permissions
✓ should return 200
STATE: auth-server provides INSUFFICIENT permissions
✓ should return 403 (107ms)
STATE: session exists.
Csrf valid.
STATE: SUFFICIENT permissions
✓ should return 200
STATE: INSUFFICIENT permissions
✓ should return 403 (224ms)
Csrf invalid.
✓ should return 401 if Csrf is MISSING (132ms)
✓ should return 401 if Csrf is WRONG (133ms)
В табличном виде: XWIKI
TODO:
- [x] Валидация схемы сonfig'a (чтобы пустые значения нельзя было ввести в обязательные поля)
- [x] Интеграционные тесты для demo-приложений
- [x] Выделить mock-server в отдельную тулзу @tools/mock-server? (Возможно, завести отдельный репозиторий для тулзов)
- [x] Инструкции в README файлах.
- [x] Обсудить с Игорем и утвердить (при необходимости - исправить) формат ответов в случае различных ошибок.
- [x] В случае обращения с протухшим токеном или обнаружения протухшей сессии возвращать 444.
- [x] Проверить, заходит ли программа вообще в логику удаления сессии, по видимому нет - нужно исправить. Или вообще удалить - обсудить с Рустом.
- [x] Сделать тесты для demo-auth-nest
- [x] Решить, что делает nestjs модуль при ошибках авторизации - выкидывает HttpException, как сейчас или что-то другое?
- [ ] Авторизация при соединении через Web Socket?
- [ ] Документация кода (кроме demo-) - apiDoc
- [x] Ревью работы с исключениями (свежий взгляд).
- [x] Протестировать подключение в отсутствии Redis и с отключенной авторизацией. (скорее всего работать не будет) - ИСПРАВЛЕНО
- [ ] Добавить валидацию Identity и IJwt (class-validator)