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

Аутентификация

Аутентификация

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

В системе ЦК используется двухтокенная схема аутентификации: - Access Token — для доступа к API с коротким временем жизни - Refresh Token — для обновления access token с длительным временем жизни

Это обеспечивает баланс между безопасностью и удобством использования.

Вход в систему

🛠️ SDK: Mutations.Auth.Login | 🔗 GraphQL API: Mutation.login

import { Mutations } from '@coopenomics/sdk';

const variables: Mutations.Auth.Login.IInput = {
  data: {
    email: <string>; // Электронная почта
    now: <string>; // Метка времени в строковом формате ISO
    signature: <string>; // Цифровая подпись метки времени
  };
};

const { [Mutations.Auth.Login.name]: result } = await client.Mutation(
  Mutations.Auth.Login.mutation,
  { variables }
);

Результат:

interface IOutput {
  login: {
    account: {
      blockchain_account?: {
        account_name: <string>; // Имя аккаунта
        core_liquid_balance?: <null | string>; // Баланс
        cpu_limit: {
          available: <string>; // Доступные ресурсы
          current_used?: <null | string>; // Текущее использование ресурсов
          last_usage_update_time?: <null | string>; // Время последнего обновления использования ресурсов
          max: <string>; // Максимальное количество ресурсов
          used: <string>; // Использовано ресурсов
        };
        cpu_weight: <string>; // Вес CPU
        created: <string>; // Дата создания
        head_block_num: <number>; // Номер последнего блока
        head_block_time: <string>; // Время последнего блока
        last_code_update: <string>; // Время последнего обновления кода
        net_limit: {
          available: <string>; // Доступные ресурсы
          current_used?: <null | string>; // Текущее использование ресурсов
          last_usage_update_time?: <null | string>; // Время последнего обновления использования ресурсов
          max: <string>; // Максимальное количество ресурсов
          used: <string>; // Использовано ресурсов
        };
        net_weight: <string>; // Вес сети
        permissions: <{
            parent: <string>; // Родительское разрешение
            perm_name: <string>; // Имя разрешения
            required_auth: {
              accounts: <{
                  permission: {
                    actor: <string>; // Актор
                    permission: <string>; // Разрешение
                  };
                  weight: <number>; // Вес
                }[]>; // Уровни разрешений
              keys: <{
                  key: <string>; // Ключ
                  weight: <number>; // Вес
                }[]>; // Ключи
              threshold: <number>; // Порог
              waits: <{
                  wait_sec: <number>; // Время ожидания в секундах
                  weight: <number>; // Вес
                }[]>; // Вес ожидания
            };
          }[]>; // Разрешения
        privileged: <boolean>; // Флаг привилегий
        ram_quota: <number>; // Квота RAM
        ram_usage: <number>; // Использование RAM
        refund_request?: {
          cpu_amount: <string>; // Сумма CPU
          net_amount: <string>; // Сумма сети
          owner: <string>; // Владелец
          request_time: <string>; // Время запроса
        };
        rex_info?: <null | string>; // Информация о REX
        self_delegated_bandwidth?: {
          cpu_weight: <string>; // Вес CPU
          from: <string>; // Отправитель
          net_weight: <string>; // Вес сети
          to: <string>; // Получатель
        };
        total_resources?: {
          cpu_weight: <string>; // Вес CPU
          net_weight: <string>; // Вес сети
          owner: <string>; // Владелец
          ram_bytes: <number>; // Используемая RAM
        };
        voter_info?: <null | string>; // Информация о голосовании
      };
      participant_account?: {
        braname?: <null | string>; // Имя кооперативного участка
        created_at: <unknown>; // Время создания записи о члене
        has_vote: <boolean>; // LEGACY Флаг, имеет ли член право голоса
        initial_amount?: <null | string>; // Сумма вступительного взноса
        is_initial: <boolean>; // LEGACY Флаг, внесен ли регистрационный взнос
        is_minimum: <boolean>; // LEGACY Флаг, внесен ли минимальный паевый взнос
        last_min_pay: <unknown>; // Время последнего минимального платежа
        last_update: <unknown>; // Время последнего обновления информации о члене
        minimum_amount?: <null | string>; // Сумма минимального паевого взноса
        status: <string>; // Статус члена кооператива (accepted | blocked)
        type?: <null | string>; // Тип участника (individual | entrepreneur | organization)
        username: <string>; // Уникальное имя члена кооператива
      };
      private_account?: {
        entrepreneur_data?: {
          birthdate: <string>; // Дата рождения
          city: <string>; // Город
          country: <string>; // Страна
          details: {
            inn: <string>; // ИНН
            ogrn: <string>; // ОГРН
          };
          email: <string>; // Email
          first_name: <string>; // Имя
          full_address: <string>; // Юридический адрес
          last_name: <string>; // Фамилия
          middle_name: <string>; // Отчество
          phone: <string>; // Телефон
          username: <string>; // Имя аккаунта
        };
        individual_data?: {
          birthdate: <string>; // Дата рождения
          email: <string>; // Email
          first_name: <string>; // Имя
          full_address: <string>; // Полный адрес
          last_name: <string>; // Фамилия
          middle_name: <string>; // Отчество
          passport?: {
            code: <string>; // Код подразделения
            issued_at: <string>; // Дата выдачи
            issued_by: <string>; // Кем выдан
            number: <number>; // Номер паспорта
            series: <number>; // Серия паспорта
          };
          phone: <string>; // Телефон
          username: <string>; // Имя аккаунта
        };
        organization_data?: {
          city: <string>; // Город
          country: <string>; // Страна
          details: {
            inn: <string>; // ИНН
            kpp: <string>; // КПП
            ogrn: <string>; // ОГРН
          };
          email: <string>; // Email
          fact_address: <string>; // Фактический адрес
          full_address: <string>; // Юридический адрес
          full_name: <string>; // Полное название
          phone: <string>; // Телефон
          represented_by: {
            based_on: <string>; // На основании чего действует
            first_name: <string>; // Имя
            last_name: <string>; // Фамилия
            middle_name: <string>; // Отчество
            position: <string>; // Должность
          };
          short_name: <string>; // Краткое название
          type: <string>; // Тип организации
          username: <string>; // Имя аккаунта организации
        };
        type: <AccountType>; // Тип аккаунта
      };
      provider_account?: {
        email: <string>; // Электронная почта пользователя
        has_account: <boolean>; // Есть ли у пользователя аккаунт
        initial_order?: <null | string>; // ID начального заказа
        is_email_verified: <boolean>; // Подтверждена ли электронная почта
        is_registered: <boolean>; // Зарегистрирован ли пользователь
        message?: <null | string>; // Сообщение
        public_key: <string>; // Публичный ключ пользователя
        referer: <string>; // Реферер пользователя
        role: <string>; // Роль пользователя
        status: <UserStatus>; // Статус пользователя
        subscriber_hash: <string>; // Хэш подписчика для уведомлений
        subscriber_id: <string>; // Идентификатор подписчика для уведомлений
        type: <string>; // Тип пользователя
        username: <string>; // Имя пользователя
      };
      user_account?: {
        meta: <string>; // Метаинформация
        referer: <string>; // Реферал
        registered_at: <string>; // Дата регистрации
        registrator: <string>; // Регистратор
        status: <string>; // Статус аккаунта
        storages: <string[]>; // Список хранилищ
        type: <string>; // Тип учетной записи
        username: <string>; // Имя аккаунта
        verifications: <{
            created_at: <string>; // Дата создания верификации
            is_verified: <boolean>; // Флаг верификации
            last_update: <string>; // Дата последнего обновления верификации
            notice: <string>; // Заметка верификации
            procedure: <string>; // Процедура верификации
            verificator: <string>; // Имя верификатора
          }[]>; // Дата регистрации
      };
      username: <string>; // Имя аккаунта кооператива
    };
    tokens: {
      access: {
        expires: <unknown>; // Дата истечения токена доступа
        token: <string>; // Токен доступа
      };
      refresh: {
        expires: <unknown>; // Дата истечения токена доступа
        token: <string>; // Токен доступа
      };
    };
  };
}

Процесс входа в систему: 1. Клиент отправляет имя пользователя 2. Сервер возвращает случайный challenge 3. Клиент подписывает challenge приватным ключом 4. Сервер проверяет подпись и выдает токены

Обновление токена

🛠️ SDK: Mutations.Auth.Refresh | 🔗 GraphQL API: Mutation.refresh

import { Mutations } from '@coopenomics/sdk';

const variables: Mutations.Auth.Refresh.IInput = {
  data: {
    access_token: <string>; // Токен доступа
    refresh_token: <string>; // Токен обновления
  };
};

const { [Mutations.Auth.Refresh.name]: result } = await client.Mutation(
  Mutations.Auth.Refresh.mutation,
  { variables }
);

Результат:

interface IOutput {
  refresh: {
    account: {
      blockchain_account?: {
        account_name: <string>; // Имя аккаунта
        core_liquid_balance?: <null | string>; // Баланс
        cpu_limit: {
          available: <string>; // Доступные ресурсы
          current_used?: <null | string>; // Текущее использование ресурсов
          last_usage_update_time?: <null | string>; // Время последнего обновления использования ресурсов
          max: <string>; // Максимальное количество ресурсов
          used: <string>; // Использовано ресурсов
        };
        cpu_weight: <string>; // Вес CPU
        created: <string>; // Дата создания
        head_block_num: <number>; // Номер последнего блока
        head_block_time: <string>; // Время последнего блока
        last_code_update: <string>; // Время последнего обновления кода
        net_limit: {
          available: <string>; // Доступные ресурсы
          current_used?: <null | string>; // Текущее использование ресурсов
          last_usage_update_time?: <null | string>; // Время последнего обновления использования ресурсов
          max: <string>; // Максимальное количество ресурсов
          used: <string>; // Использовано ресурсов
        };
        net_weight: <string>; // Вес сети
        permissions: <{
            parent: <string>; // Родительское разрешение
            perm_name: <string>; // Имя разрешения
            required_auth: {
              accounts: <{
                  permission: {
                    actor: <string>; // Актор
                    permission: <string>; // Разрешение
                  };
                  weight: <number>; // Вес
                }[]>; // Уровни разрешений
              keys: <{
                  key: <string>; // Ключ
                  weight: <number>; // Вес
                }[]>; // Ключи
              threshold: <number>; // Порог
              waits: <{
                  wait_sec: <number>; // Время ожидания в секундах
                  weight: <number>; // Вес
                }[]>; // Вес ожидания
            };
          }[]>; // Разрешения
        privileged: <boolean>; // Флаг привилегий
        ram_quota: <number>; // Квота RAM
        ram_usage: <number>; // Использование RAM
        refund_request?: {
          cpu_amount: <string>; // Сумма CPU
          net_amount: <string>; // Сумма сети
          owner: <string>; // Владелец
          request_time: <string>; // Время запроса
        };
        rex_info?: <null | string>; // Информация о REX
        self_delegated_bandwidth?: {
          cpu_weight: <string>; // Вес CPU
          from: <string>; // Отправитель
          net_weight: <string>; // Вес сети
          to: <string>; // Получатель
        };
        total_resources?: {
          cpu_weight: <string>; // Вес CPU
          net_weight: <string>; // Вес сети
          owner: <string>; // Владелец
          ram_bytes: <number>; // Используемая RAM
        };
        voter_info?: <null | string>; // Информация о голосовании
      };
      participant_account?: {
        braname?: <null | string>; // Имя кооперативного участка
        created_at: <unknown>; // Время создания записи о члене
        has_vote: <boolean>; // LEGACY Флаг, имеет ли член право голоса
        initial_amount?: <null | string>; // Сумма вступительного взноса
        is_initial: <boolean>; // LEGACY Флаг, внесен ли регистрационный взнос
        is_minimum: <boolean>; // LEGACY Флаг, внесен ли минимальный паевый взнос
        last_min_pay: <unknown>; // Время последнего минимального платежа
        last_update: <unknown>; // Время последнего обновления информации о члене
        minimum_amount?: <null | string>; // Сумма минимального паевого взноса
        status: <string>; // Статус члена кооператива (accepted | blocked)
        type?: <null | string>; // Тип участника (individual | entrepreneur | organization)
        username: <string>; // Уникальное имя члена кооператива
      };
      private_account?: {
        entrepreneur_data?: {
          birthdate: <string>; // Дата рождения
          city: <string>; // Город
          country: <string>; // Страна
          details: {
            inn: <string>; // ИНН
            ogrn: <string>; // ОГРН
          };
          email: <string>; // Email
          first_name: <string>; // Имя
          full_address: <string>; // Юридический адрес
          last_name: <string>; // Фамилия
          middle_name: <string>; // Отчество
          phone: <string>; // Телефон
          username: <string>; // Имя аккаунта
        };
        individual_data?: {
          birthdate: <string>; // Дата рождения
          email: <string>; // Email
          first_name: <string>; // Имя
          full_address: <string>; // Полный адрес
          last_name: <string>; // Фамилия
          middle_name: <string>; // Отчество
          passport?: {
            code: <string>; // Код подразделения
            issued_at: <string>; // Дата выдачи
            issued_by: <string>; // Кем выдан
            number: <number>; // Номер паспорта
            series: <number>; // Серия паспорта
          };
          phone: <string>; // Телефон
          username: <string>; // Имя аккаунта
        };
        organization_data?: {
          city: <string>; // Город
          country: <string>; // Страна
          details: {
            inn: <string>; // ИНН
            kpp: <string>; // КПП
            ogrn: <string>; // ОГРН
          };
          email: <string>; // Email
          fact_address: <string>; // Фактический адрес
          full_address: <string>; // Юридический адрес
          full_name: <string>; // Полное название
          phone: <string>; // Телефон
          represented_by: {
            based_on: <string>; // На основании чего действует
            first_name: <string>; // Имя
            last_name: <string>; // Фамилия
            middle_name: <string>; // Отчество
            position: <string>; // Должность
          };
          short_name: <string>; // Краткое название
          type: <string>; // Тип организации
          username: <string>; // Имя аккаунта организации
        };
        type: <AccountType>; // Тип аккаунта
      };
      provider_account?: {
        email: <string>; // Электронная почта пользователя
        has_account: <boolean>; // Есть ли у пользователя аккаунт
        initial_order?: <null | string>; // ID начального заказа
        is_email_verified: <boolean>; // Подтверждена ли электронная почта
        is_registered: <boolean>; // Зарегистрирован ли пользователь
        message?: <null | string>; // Сообщение
        public_key: <string>; // Публичный ключ пользователя
        referer: <string>; // Реферер пользователя
        role: <string>; // Роль пользователя
        status: <UserStatus>; // Статус пользователя
        subscriber_hash: <string>; // Хэш подписчика для уведомлений
        subscriber_id: <string>; // Идентификатор подписчика для уведомлений
        type: <string>; // Тип пользователя
        username: <string>; // Имя пользователя
      };
      user_account?: {
        meta: <string>; // Метаинформация
        referer: <string>; // Реферал
        registered_at: <string>; // Дата регистрации
        registrator: <string>; // Регистратор
        status: <string>; // Статус аккаунта
        storages: <string[]>; // Список хранилищ
        type: <string>; // Тип учетной записи
        username: <string>; // Имя аккаунта
        verifications: <{
            created_at: <string>; // Дата создания верификации
            is_verified: <boolean>; // Флаг верификации
            last_update: <string>; // Дата последнего обновления верификации
            notice: <string>; // Заметка верификации
            procedure: <string>; // Процедура верификации
            verificator: <string>; // Имя верификатора
          }[]>; // Дата регистрации
      };
      username: <string>; // Имя аккаунта кооператива
    };
    tokens: {
      access: {
        expires: <unknown>; // Дата истечения токена доступа
        token: <string>; // Токен доступа
      };
      refresh: {
        expires: <unknown>; // Дата истечения токена доступа
        token: <string>; // Токен доступа
      };
    };
  };
}

Refresh token имеет более длительное время жизни и используется для получения новых access token без повторной аутентификации.

Выход из системы

🛠️ SDK: Mutations.Auth.Logout | 🔗 GraphQL API: Mutation.logout

import { Mutations } from '@coopenomics/sdk';

const variables: Mutations.Auth.Logout.IInput = {
  data: {
    access_token: <string>; // Токен обновления
    refresh_token: <string>; // Токен доступа
  };
};

const { [Mutations.Auth.Logout.name]: result } = await client.Mutation(
  Mutations.Auth.Logout.mutation,
  { variables }
);

Результат:

interface IOutput {
  logout: <boolean>; // Выйти из системы и заблокировать JWT-токены
}

При выходе из системы refresh token добавляется в черный список, что делает невозможным его дальнейшее использование.

Роли и права доступа

Система поддерживает следующие роли:

  • chairman — председатель совета (полные права)

  • member — член совета (ограниченные права)

  • user — пайщик (минимальные права)

Установка прав доступа осуществляется автоматически на основании событий блокчейна, таких как приём нового пайщика или добавления пайщика в совет кооператива. Проверка прав доступа осуществляется для каждого GraphQL запроса/мутации/подписки.