API ModusBI: Аутентификация пользователя и работа с токеном сессии - Публичная база знаний Modus
Почти все команды ModusBI API требуют активной сессии пользователя. Исключения составляют команды входа, команды EULA и несколько публичных эндпоинтов (см. раздел «Команды без токена»).
Для выполнения защищенных запросов внешнее приложение должно пройти процесс аутентификации и получить токен сессии. Токен передается в каждом последующем вызове API.
Команда login/create
Команда login/create выполняет аутентификацию пользователя и возвращает параметры учетной записи. В случае необходимости принятия пользовательского соглашения EULA процесс аутентификации прерывается до принятия соглашения.
Запрос:
- URL:
<protocol>://<host>/<path_to_api>/login - Пример URL:
https://dev.modusbi.ru/v1/api/login - Тип запроса: POST;
- Тип данных тела запроса: JSON.
Тело запроса:
{
"object": {"name": "login"},
"command": {"name": "create"},
"data": [{
"username": "admin",
"password": "********",
"pcid": 1
}]
}
Параметры:
| Поле | Назначение |
|---|---|
username |
Логин пользователя портала |
password |
Пароль |
pcid |
Идентификатор конфигурации провайдера аутентификации. Для встроенного входа ModusBI обычно 1. Если передать 0 или опустить — сервер подставит провайдер по умолчанию для пользователя или портала |
Пример curl:
curl -s -X POST 'https://<host>/v1/api/login' \
-H 'Content-Type: application/json' \
-d '{
"object": {"name": "login"},
"command": {"name": "create"},
"data": [{"username": "admin", "password": "********", "pcid": 1}]
}'
Справочник: login/create.
Что делает сервер (пошагово)
Клиент отправляет один HTTP-запрос login/create. Внутри сервер выполняет цепочку шагов — отдельно вызывать их не нужно. Ниже в таблице перечислен порядок обработки входа и соответствующий ответ клиенту:
| № | Этап | Что происходит | Результат для клиента |
|---|---|---|---|
| 1 | Проверка параметров | Валидация username, password, pcid |
При ошибке — status ≠ 200, сообщение в message |
| 2 | Выбор провайдера | По pcid загружается конфигурация аутентификации (локальный ModusBI, LDAP, OAuth и т.д.) |
— |
| 3 | Аутентификация | Проверка логина и пароля (или сценарий внешнего провайдера) | «Неверный Пользователь или Пароль», блокировка учетной записи (УЗ) и др. |
| 4 | Состояние УЗ | Проверка, что учетная запись активна, не истекла | Сообщение в message или loginMessage |
| 5 | Профиль и роль | Назначение роли, профилей доступа, переменных пользователя | Служебные шаги, в ответе не видны |
| 6 | Проверка EULA | Сравнение принятой пользователем версии соглашения с актуальной | Если не принято — ветка EULA (токен не выдается) |
| 7 | Создание сессии | Открытие сеанса, генерация JWT | — |
| 8 | Формирование ответа | Запись события входа, сбор данных профиля | data.token, roleID, permissions, ФИО и др. |
Варианты ответа login/create
Сервер возвращает HTTP-код 200 при успешной обработке запроса, однако наличие этого кода не гарантирует выдачу токена. Возможны следующие сценарии:
1. Аутентификация пройдена, принятие EULA не требуется.
Сохраните data.token. Остальные поля (roleID, permissions, username и т.д.) описывают учетную запись.
{
"mode": "online",
"status": 200,
"message": "",
"data": {
"ID": 1,
"username": "admin",
"roleID": 1,
"roleName": "Администратор",
"token": "eyJ0eXAiOiJKV1QiLCJhbGci...",
"permissions": [{"edit": 1, "settings": 1, "view": 1}],
"loginMessage": ""
}
}
Обратите внимание на поле loginMessage. Если оно содержит текст, покажите это сообщение пользователю, так как оно информирует о статусе учетной записи (например, о скором истечении срока действия).
2. Аутентификация пройдена, требуется принятие EULA.
Сервер возвращает HTTP-код 200, но поле data.token отсутствует. Вместо него приходят флаг ожидания и идентификатор отложенных данных:
{
"mode": "online",
"status": 200,
"message": "",
"data": {
"eulaAcceptancePending": true,
"pendingID": "e414c5c7-9b2f-48e0-ae89-39b039434444"
}
}
В этом сценарии токен не выдается. Для продолжения процесса выполните шаги, описанные в разделе «Пользовательское соглашение (EULA)». Повторно вызывать login/create с тем же логином не нужно, пока действует pendingID (15 минут).
3. Ошибка входа.
Любой HTTP-код, отличный от 200 (status ≠ 200), либо наличие текста в поле message свидетельствуют об ошибке.
Типичные случаи:
- неверный логин или пароль;
- учетная запись заблокирована или неактивна;
- неверный или неподходящий
pcid(провайдер аутентификации).
4. Внешний провайдер (HTTP 301).
Для pcid внешней системы (Keycloak, OAuth, ЕСИА и т.п.) сервер может вернуть редирект на страницу IdP вместо JSON с токеном. Клиент обрабатывает переход по правилам провайдера. После успешной аутентификации на стороне внешней системы сценарий завершается ответом с data.token или веткой EULA.
Пользовательское соглашение (EULA)
ModusBI может требовать принятия пользовательского соглашения (EULA) перед выдачей токена. Проверка выполняется после успешной проверки логина и пароля, но до создания сессии и поля data.token.
Тип соглашения зависит от лицензии сервера:
| Тип лицензии | Тип соглашения в БД |
|---|---|
| Стандартный | commercial |
| Любой иной (ограниченный, пробный и т.д.) | trial |
Текст хранится в метаданных (таблица eula, с поддержкой языков). Подробности для администраторов: Пользовательское соглашение (EULA).
EULA не запрашивается, если:
- включен режим White Label (
ServerWhiteLabel); - для типа лицензии нет записей EULA в метаданных;
- пользователь уже принял актуальную версию соглашения для своего типа лицензии;
- версия фронтенда ниже 3.15.0 (проверка EULA отключена).
В этих случаях login/create сразу возвращает data.token.
Полный сценарий для клиента API
Шаг EULA-1. Ответ login/create с pendingID
После успешной проверки пароля сервер не выдает токен, а сохраняет отложенные данные входа в памяти сервера и возвращает UUID — pendingID.
В отложенной записи хранятся: идентификатор пользователя, pcid, параметры сессии, eula_id текста, который нужно показать.
Важно:
pendingIDдействует 15 минут с момента выдачи. После истечения или перезапуска сервера запись теряется — нужен новыйlogin/create.- Команды
eula.get_textиeula.resolveвыполняются без заголовкаAuthorization. - Повторный
login/createдо завершения EULA создаст новыйpendingID— используйте тот, что пришел в последнем ответе.
Шаг EULA-2. Получение текста — login/eula.get_text
Команда возвращает текст пользовательского соглашения по идентификатору отложенных данных, выданных в ответе login/create (или login/bind_ids) в варианте ожидания принятия EULA.
Запрос:
- URL:
<protocol>://<host>/<path_to_api>/login - Пример URL:
https://dev.modusbi.ru/v1/api/login - Тип запроса: POST;
- Тип данных тела запроса: JSON.
{
"object": {"name": "login"},
"command": {"name": "eula.get_text"},
"data": [{
"pendingID": "e414c5c7-9b2f-48e0-ae89-39b039434444"
}]
}
Обязательный параметр: pendingID – строка, идентификатор отложенных данных.
При успешном выполнении (код 200) сервер возвращает текст соглашения в поле data.eulaText:
{
"mode": "online",
"status": 200,
"message": "",
"data": {
"eulaText": "<p>Текст пользовательского соглашения...</p>"
}
}
Тело ответа:
$.data.eulaText— Строка — Текст EULA;$.message— Строка — Сообщение об ошибке (пусто при успехе);$.status— Число — 200 - успех; иначе - ошибка;$.mode— Строка — Состояние сервиса портала;
Поле data.eulaText может содержать HTML-разметку. Отобразите полученный текст пользователю в интерфейсе приложения.
Иные коды ответа свидетельствуют о ошибке.
Пример curl:
curl -s -X POST 'https://<host>/v1/api/login' \
-H 'Content-Type: application/json' \
-d '{
"object": {"name": "login"},
"command": {"name": "eula.get_text"},
"data": [{"pendingID": "e414c5c7-9b2f-48e0-ae89-39b039434444"}]
}'
Справочник: login/eula.get_text.
Возможные ошибки:
| Ситуация | Сообщение (публичная часть) |
|---|---|
Не передан pendingID |
Не передан идентификатор отложенных данных |
| Нет отложенной записи / истек срок (15 мин) | Запись отложенных данных не найдена или истекла |
Нет текста по eula_id в БД |
Соглашение не найдено в метаданных |
Шаг EULA-3. Принятие или отклонение — login/eula.resolve
Команда обрабатывает решение пользователя о принятии или отклонении EULA. Вызывается после того, как пользователь просмотрел текст (полученный отдельной командой eula.get_text по pendingID).
При принятии — сохраняет актуальную версию EULA в профиле пользователя (для типа соглашения по лицензии сервера) и завершает процесс аутентификации пользователя. При отклонении — завершает цепочку входа без авторизации (AccessAllow=false): токен и данные успешного логина не выдаются.
Запрос:
- URL:
<protocol>://<host>/<path_to_api>/login - Пример URL:
https://dev.modusbi.ru/v1/api/login - Тип запроса: POST;
- Тип данных тела запроса: JSON;
Принятие (пользователь согласился):
{
"object": {"name": "login"},
"command": {"name": "eula.resolve"},
"data": [{
"pendingID": "e414c5c7-9b2f-48e0-ae89-39b039434444",
"eulaAccepted": true
}]
}
При eulaAccepted: true сервер:
- Сохраняет в профиле пользователя принятую версию EULA.
- Продолжает прерванную цепочку входа (создание сессии, формирование JWT).
- Возвращает ответ такой же по структуре, как успешный
login/create— сdata.tokenи полями профиля.
Отклонение (пользователь не согласился):
{
"object": {"name": "login"},
"command": {"name": "eula.resolve"},
"data": [{
"pendingID": "e414c5c7-9b2f-48e0-ae89-39b039434444",
"eulaAccepted": false
}]
}
При eulaAccepted: false:
- токен не выдается;
- данные профиля и
tokenв ответ не приходят; - для доступа к API нужен новый цикл с
login/create; - тело ответа содержит только служебные поля и не включает данные профиля или токен (поле
data— пустой массив, полей профиля и token нет):
{ "mode":"online", "status":200, "message":"", "data":[] }
Пример curl (принятие):
curl -s -X POST 'https://<host>/v1/api/login' \
-H 'Content-Type: application/json' \
-d '{
"object": {"name": "login"},
"command": {"name": "eula.resolve"},
"data": [{
"pendingID": "e414c5c7-9b2f-48e0-ae89-39b039434444",
"eulaAccepted": true
}]
}'
Справочник: login/eula.resolve.
Возможные ошибки:
| Ситуация | Сообщение (публичная часть) |
|---|---|
Не передан pendingID |
Не передан идентификатор pending |
| Нет отложенной записи / истек срок (15 мин) | Запись EULA не найдена или истекла |
Важно: pendingID действует 15 минут с момента выдачи. При истечении этого срока или перезапуске сервера запись теряется. В этом случае необходимо заново выполнить команду login/create.
Сводная таблица команд EULA
| Шаг | Команда | Authorization | Что возвращает |
|---|---|---|---|
| 1 | login/create |
нет | pendingID или сразу token |
| 2 | login/eula.get_text |
нет | data.eulaText |
| 3 | login/eula.resolve |
нет | при принятии — data.token как при успешном входе |
Повторное принятие после обновления EULA
Администратор может опубликовать новую версию соглашения в метаданных. При следующем login/create пользователи, принявшие старую версию, снова получат eulaAcceptancePending и пройдут шаги eula.get_text → eula.resolve.
Использование токена
Поле data.token (из login/create или из eula.resolve при принятии) — это JWT-маркер сессии. Передавайте его в каждом защищенном запросе к API.
Заголовок запроса:
Authorization: Bearer <значение data.token>
Content-Type: application/json
Префикс Bearer и пробел перед токеном обязательны. Токен передается как строка, без кавычек.
Токен привязан к серверной сессии. При завершении сеанса (выход, таймаут, административное завершение) API вернет сообщение об ошибке, например: «Сеанс пользователя завершен» или «Необходимо повторно пройти аутентификацию». В этом случае выполните login/create заново.
Один токен предназначен для серии запросов. Не вызывайте команду входа перед каждой командой.
Query-параметр (редко):
auth_token=<token>в URL — для открытия отчета в браузере (автоэкспорт). Для JSON API — толькоAuthorization: Bearer <token>.
Команды без токена
Следующие команды не требуют заголовка Authorization:
| Команда | Объект | Назначение |
|---|---|---|
create |
login |
Вход, начало сценария |
eula.get_text |
login |
Текст соглашения по pendingID |
eula.resolve |
login |
Принятие/отказ от EULA, завершение входа |
bind_ids |
login |
Связывание внешнего ID (может вернуть ветку EULA) |
list.common.settings |
login |
Настройки до входа |
echo, health |
check |
Проверка доступности (GET/HEAD) |
Вызов других команд API
После получения data.token все остальные команды вызываются по единому шаблону:
POST https://<host>/v1/api/<object>
Authorization: Bearer <token>
Content-Type: application/json
{
"object": {"name": "<object>"},
"command": {"name": "<command>"},
"data": [{ ... }]
}
<object>в URL и вobject.nameсовпадают (users,datasources,reports, …);command.name— имя команды из справочника API;data— массив объектов. Для одной операции достаточно одного элемента.
Пример — справочник ролей:
curl -s -X POST 'https://<host>/v1/api/users' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{
"object": {"name": "users"},
"command": {"name": "role.list"}
}'
Пример — список источников:
curl -s -X POST 'https://<host>/v1/api/datasources' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{
"object": {"name": "datasources"},
"command": {"name": "list"}
}'
Пример — создание источника:
curl -s -X POST 'https://<host>/v1/api/datasources' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{
"object": {"name": "datasources"},
"command": {"name": "create"},
"data": [{
"parentID": 20,
"caption": "Мой источник",
"name": "my_datasource"
}]
}'
Документация: datasources/create.
Сквозной пример (вход + команда):
# 1. Вход
RESP=$(curl -s -X POST 'https://<host>/v1/api/login' \
-H 'Content-Type: application/json' \
-d '{"object":{"name":"login"},"command":{"name":"create"},"data":[{"username":"admin","password":"***","pcid":1}]}')
# 2. Если нужен EULA — обработать pendingID (get_text → resolve), иначе:
TOKEN=$(echo "$RESP" | jq -r '.data.token')
# 3. Команда с токеном
curl -s -X POST 'https://<host>/v1/api/users' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $TOKEN" \
-d '{"object":{"name":"users"},"command":{"name":"role.list"}}'