Перейти к содержанию

Core (он же Auth)

API Endpoints

Regular Auth

Базовая регистрация и авторизация (email-password).

GET /api/v1/auth/regular/register

Требования:

  • клиентское приложение

Описание: Зарегистрироваться в системе.

Корректный запрос к серверу (curl):

Bash
1
2
3
4
5
6
7
8
curl https://core.dev.goswap.app/api/v1/register \
    -X POST \
    -H "Content-Type: application/json" \
    -H "X-SWAP-CLIENT-APP-TOKEN: ..." \
    -H "X-SWAP-CLIENT-APP-FLAVOR: ..." \
    -H "X-SWAP-CLIENT-APP-STAGE: ..." \
    -H "X-SWAP-CLIENT-APP-VERSION: ..." \
    -d '{"email": "[email protected]", "password1": "your_password", "password2": "your_password", "role": "WORKER"}'
Информация

Для получения заголовков клиентских приложений (те, что X-SWAP-CLIENT-APP-{TOKEN,FLAVOR,STAGE,VERSION}) вам нужно зарегистрировать клиентское приложение.

Для этого:

  1. Переходим в админку, авторизуемся в ней

  2. После успешной авторизации переходим во вкладку Client Applications и нажимаем Create New Client Application.

  3. Внимательно заполняем все поля согласно параметрам вашего клиентского приложения.

  4. Нажимаем кнопку Save.

После чего система перебросит нас в таблицу, из которой копируем все поля в соответствующие их названиям заголовки запроса (request headers).

Корректный ответ от сервера (JSON):

JSON
1
2
3
4
5
6
7
8
{
  "access": "{long_access_token}",
  "refresh": "",
  "user": {
    "pk": "74cde4a7-bd70-409c-947a-22958344c05a",
    "email": "[email protected]"
  }
}

Обратите внимание, при регистрации в системе система автоматически производит авторизацию только что созданного пользоваетеля.

POST /api/v1/auth/regular/login

Требования:

  • клиентское приложение

Описание: Войти в систему по используемой связке email/password.

Корректный запрос к серверу (curl):

Bash
1
2
3
4
5
6
7
8
curl https://core.dev.goswap.app \
    -X POST \
    -H "Content-Type: application/json" \
    -H "X-SWAP-CLIENT-APP-TOKEN: ..." \
    -H "X-SWAP-CLIENT-APP-FLAVOR: ..." \
    -H "X-SWAP-CLIENT-APP-STAGE: ..." \
    -H "X-SWAP-CLIENT-APP-VERSION: ..." \
    -d '{"email": "[email protected]", "password": "your_swap_user_password"}'

Корректный ответ от сервера (JSON):

JSON
1
2
3
4
5
6
7
8
{
  "access": "{long_access_token}",
  "refresh": "",
  "user": {
    "pk": "74cde4a7-bd70-409c-947a-22958344c05a",
    "email": "[email protected]"
  }
}

Обратите внимание - этот токен сохраняется в cookie на доменном уровне и может переиспользоваться между сервисами. Например, залогинившись в core, мы можем спокойно продолжать работать с profile и другими сервисами.

Важно!

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

Storage

PUT /api/v1/storage/upload

Требования:

  • авторизованный пользователь
  • клиентское приложение

Описание: Загрузить несколько файлов в файловое хранилище системы SWAP.

Прикрепляем любое количество файлов, важно, чтобы их порядок соответствовал порядку метаданных, переданных в виде JSON Array.

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

Список допустимых типов файлов:

  • Документы: PDF
  • Изображения: JPG/JPEG/PNG

Корректный запрос к серверу (curl):

Bash
1
2
3
4
5
6
curl https://core.dev.goswap.app/api/v1/upload \
    -X PUT \
    -H "Content-Type: multipart/form-data" \
    -F "@file_1=asset1.pdf" \ 
    -F "@file_2=asset2.jpg" \
    -d '[{"document_type": "Passport", "caption": "My recently updated passport", "owned_by_worker": "74cde4a7-bd70-409c-947a-22958344c05a", "owned_by_company": ""}]'

Корректный ответ от сервера (JSON):

JSON
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[
    {
        "asset_id": "2c50f53a-df94-458a-a55d-e019a12d7870",
        "asset_type": "Document",
        "asset_filename": "asset1.pdf",
        "asset_download_url": "https://core.dev.goswap.app/api/v1/download/document/2c50f53a-df94-458a-a55d-e019a12d7870",
    },
    {
        "asset_id": "eda71991-9428-46fc-a0f0-b42ab7ad9376",
        "asset_type": "Image",
        "asset_filename": "asset2.jpg",
        "asset_download_url": "https://core.dev.goswap.app/api/v1/download/image/eda71991-9428-46fc-a0f0-b42ab7ad9376",
    }
]

Любые другие ответы считаются некорректными.

GET /api/v1/storage/download/{asset_type}/{asset_id}

Загрузить конкретный файл ассета типа {asset_type} по идентификатору {asset_id}. Напрямую скачивает файл с файлового хранилища в виде бинарного файла.

Корректный запрос к серверу (curl):

Bash
1
curl https://core.dev.goswap.app/api/v1/download/document/2c50f53a-df94-458a-a55d-e019a12d7870 -O passport.pdf

Корректный ответ от сервера: Успешно загруженный на локальную машину файл с сервера.

Дополнительно

Клиентское приглашение и клиентские сессии

О процессе регистрации (пошагово, поймёт даже тибетский ёж!)

  1. Компания-наниматель создаёт приглашения в систему SWAP работникам или сотрудникам компании, например, в админке. Или сразу батчем1 на несколько сотен эмэйлов работников.

    Интересный факт

    Это похоже на систему регистрации старого Хабрахабра, где регистрация была изначально по инвайтам и зарегистрированный пользователь (в нашем случае - компания) могла пригласить другого пользователя (в нашем случае - работника/или сотрудника компании) на портал. Когда регистрация на Хабре открылась для всех, по факту всех стал "приглашать" один пользователь - НЛО (сделано это было таким образом, чтобы не переделывать существующую логику регистрации). В нашем случае - компания - SWAP Administration, которая создаётся дата-миграцией при деплое (аналогично с наполнением датасетов и созданием главного пользователя - swap_admin).

  2. При создании приглашения работникам на бэкэнде автоматически регистрируются их временные2 аккаунты (со временным паролем - токеном от приглашения) и они получают письмо на свои почтовые адреса о том, что компания "SWAP Administration" (или другая - инициатор выдачи приглашений пользователям) приглашает вас зарегистрироваться в системе SWAP по уникальной ссылке.

  3. Пользователь переходит по этой ссылке (тем самым инициируя вход в систему под временным паролем)

    https://dev.goswap.app/invite/?token=bmSGyXxOrtXlhVY_ceRpzQGnlC4vfj5bvMkcl8eTpf0

    Внутри себя фронт вызывает проверку этого токена:

    HTTP
    1
    POST core.dev.goswap.app/api/v1/client-invitations/verify-token/bmSGyXxOrtXlhVY_ceRpzQGnlC4vfj5bvMkcl8eTpf0
    

    И если токен валиден, проверка возвращает ему email пользователя в пэйлоуде. Дальше фронт логинит пользователя.

    HTTP
    1
    2
    POST core.dev.goswap.app/api/v1/auth/regular/login
    {"email": "[email protected]", "password": "bmSGyXxOrtXlhVY_ceRpzQGnlC4vfj5bvMkcl8eTpf0"}
    

    И помещает вернувшиеся access_token и verify_token из пэйлоуда в cookies после успешного входа в систему.

    Фронты, внимание!

    Вы выполняете этот запрос по загрузке урла из email. Проще говоря - пользователь должен быть уже залогинен в свой временный аккаунт, когда зайдёт на экран с установкой пароля. Иначе пароль не сменится! POST core.dev.goswap.app/api/v1/auth/regular/password/change работает только для активного (то есть залогинившегося) пользователя!

    Вопрос: а может ли залогинить пользователя бэк и вернуть хидеры авторизации в verify token?

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

  4. Авторизовавшись (бесшовно для фронта), пользователь попадает на страницу создания нового пароля (экран 1.0). Ему остаётся только поменять временный пароль на свой и установить дату рождения, ФИО и т.д. Это два запроса:

    1. Смена пароля
    HTTP
    1
    2
    POST core.dev.goswap.app/api/v1/auth/regular/password/change/
    {"new_password1": "<new_password>", "new_password2": "<new_password>"}
    
    1. Обновление данных аккаунта
    HTTP
    1
    2
    PATCH core.dev.goswap.app/api/v1/auth/regular/user/
    {... updated fields of GET core.dev.goswap.app/api/v1/auth/regular/user/ response payload ...}
    

Однако фронтам стоит учесть, что созданный аккаунт временный (вы получите эту инфу в результате выполнения запроса POST core.dev.goswap.app/api/v1/auth/regular/login/ в поле "is_verified": false объекта user) и после запроса на сохранение данных запросить ещё отправку верификационного email, выполнив следующий запрос:

HTTP
1
2
POST core.dev.goswap.app/api/v1/auth/regular/verify-email/
{"key": "[email protected]"}

О клиентских сессиях

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

Сейчас объясню на примере.

Условно, начал работник заполнение профиля в телефоне, затем понял, что некоторые документы у него только на компе и решил перейти на комп. И чтобы ему не вводить всё по новой - мы сохраняем состояние его клиентской сессии в БД. Затем, когда он переходит за комп, и авторизуется в системе - мы находим открытую его сессию на телефоне с данными форм и переносим их на комп. После чего сессию на телефоне мы можем закрыть или оставить. Любые изменения в формах на фронте влекут за собой вызов следующего запроса:

HTTP
1
2
PATCH core.dev.goswap.app/api/v1/client-sessions/{session_id}
{"filled_fields": {"<form_name>": {...updated fields }}}
Фронты, внимание!

Этот запрос полностью меняет содержимое полей (не prepend, а замена!), поэтому вы должны отправлять мне ВСЕ поля, включая неизменённые. Возможно в дальнейшем я поправлю эту логику, когда пойму, как лучше сделать.

Как это всё работает (диаграмма)

flowchart TD
    %% nodes description

    node_start((start))
    node_end((end))
    step1["
        Компания создаёт приглашение (в бэкофисе или джанговской админке сервиса core) для конкретного пользователя по его email.
        При создании приглашения автоматически генерируется пригласительная ссылка,
        вида <a href='#'>https://dev.goswap.app/invite/?token=GBg6QtXM_w4ORw5ZzE5k2ErmH7yJGrOqhHT6E5bHGvE</a>
        и пользователю автоматически создаётся (если не был создан) аккаунт на бэкэнде по его email со временным паролем.
    "]
    step2["
        По этой ссылке осуществляется переход на фронтэнд.
    "]
    step3["
        На фронтэнде проверяется валидность токена <code>GBg6QtXM_w4ORw5ZzE5k2ErmH7yJGrOqhHT6E5bHGvE</code>
        посредством отправки на бэкэнд запроса POST <a href='#'>https://core.dev.goswap.app/api/v1/client-invitations/verify-token/GBg6QtXM_w4ORw5ZzE5k2ErmH7yJGrOqhHT6E5bHGvE</a>
    "]
    step4{"Токен валидный (т.е. существует и не просрочен?)"}
    step5["404 Not Found (если не существует) или 410 Gone (если просрочен)"]
    step6["
        Фронтэнд генерирует Id сессии и отправляет на бэкэнд POST запрос для открытия новой сессии (не забывая прикрепить хидеры клиентского приложения).
        POST <a href="">https://core.dev.goswap.app/api/v1/client-sessions/{session_id}</a>
    "]
    step7["
        Когда сессия открылась, фронтэнд забирает <code>session_id</code> из вернувшегося пэйлоуда и использует его для авторизации сессии либо
        в header <code>X-SWAP-CLIENT-SESSION-ID</code>, либо в cookie <code>swap_client_session_id</code>
    "]
    step8["
        Проверить состояние сессии можно в любой момент по запросу
        GET <a href>https://core.dev.goswap.app/api/v1/client-sessions/{session_id}</a>
        (не забываем прикрепить хидеры клиентского приложения)
        Если сессия просрочилась - вернётся 410 Gone.
        Если сессии с таким <code>session_id</code> не существует - вернётся 404 Not found.
        В противном случае вернётся следующая детализация сессии:
        {'id': '3f087e5f-3e07-4d31-a625-8fc1d1d597c3', 'expired_at': '2025-08-01T08:03:36.850059Z', 'created_at': '2025-07-31T08:03:36.850059Z', 'updated_at': '2025-07-31T08:03:36.850079Z', 'session_id': 'aSjrlYnFhsWrOeE1y0d38VyZsq47nzFddOWWfq2HPic', 'token': 'DfIsocWnQrZAHT65cJmIpZoWvH_k7hJyTBCICFDhWro', 'time_to_live': 86400}
    "]

    %% flowchart
    node_start --> step1
    step1 --> step2
    step2 --> step3
    step3 --> step4
    step4 --> |Нет| step5
    step4 --> |Да| step6
    step5 --> step1
    step6 --> step7
    step7 --> step8
    step8 --> node_end

  1. то есть выслать множество приглашений одним запросом на множество emails сразу, например

    HTTP
    1
    2
    3
    4
    5
    6
    POST core.dev.goswap.app/api/v1/client-invitations/batch
    {
        "invited_by_company": "{company_uuid}",
        "invited_workers_emails": ["[email protected]", "[email protected]", ..., "[email protected]"],
        "invited_employee_emails": ["[email protected]", "[email protected]", ..., "[email protected]"]
    }
    
     

  2. временные - потому что все неверифицированные аккаунты чистятся определённой таской в кронтабе, условно - раз в неделю