Аутентификация и роли

Обзор

Private Channels включает опциональный Auth Service, который ограничивает доступ к шлюзу с помощью JWT-аутентификации и управления доступом на основе ролей (RBAC). Когда аутентификация отключена, шлюз принимает все подключения. Когда она включена, клиенты должны передавать действительный JWT в каждом запросе.

Эта страница охватывает обе аудитории:

  • Разработчики — регистрация, вход, верификация кошелька и выполнение аутентифицированных запросов
  • Операторы — включение auth service, настройка JWT_SECRET и назначение роли operator

Включение аутентификации

Аутентификация включается путём установки JWT_SECRET (непустого значения) как на шлюзе, так и в Auth Service. Auth Service также требует AUTH_DATABASE_URL.

Если JWT_SECRET не задан, шлюз работает в открытом режиме — токен не требуется.

Docker Compose: Auth service является профилем Docker Compose и по умолчанию не запускается. Чтобы включить его, передайте --profile auth в команду docker compose, а также --env-file .env, чтобы секреты, такие как JWT_SECRET и POSTGRES_PASSWORD, корректно разрешались (Compose отключает автоматическую загрузку .env, как только передаётся любой флаг --env-file):

docker compose -f docker-compose.devnet.yml --env-file versions.env --env-file .env.devnet --env-file .env --profile auth up -d

API Auth Service

Все эндпоинты находятся по пути /auth. Auth service слушает на порту AUTH_PORT (по умолчанию 8903).

POST /auth/register

Создать новый аккаунт. Все пользователи регистрируются с ролью user.

{ "username": "alice", "password": "hunter2" }
  • Имя пользователя: 5–32 символа, буквенно-цифровые плюс _ и -
  • Пароль: 6–128 символов
  • Возвращает созданного пользователя; пароль никогда не возвращается

POST /auth/login

Выполнить аутентификацию и получить подписанный JWT, действительный в течение 24 часов.

{ "username": "alice", "password": "hunter2" }

Возвращает { "token": "<jwt>" }. Неверное имя пользователя и неверный пароль оба возвращают 401, чтобы предотвратить перебор имён пользователей.

POST /auth/challenge-wallet

Запросить challenge для подписи с целью подтверждения владения кошельком Solana. Требуется действительный JWT.

Возвращает сообщение, nonce и время истечения. Challenge действителен в течение 10 минут.

{
"message": "PrivateChannel wallet verification\nuser: <uuid>\nnonce: <uuid>\nexpires: <unix>",
"nonce": "<uuid>",
"expires_at": "<iso8601>"
}

POST /auth/verify-wallet

Отправить подписанный challenge для регистрации кошелька как верифицированного. Требуется действительный JWT.

{
"pubkey": "<base58 pubkey>",
"nonce": "<uuid from challenge>",
"signature": "<base58 Ed25519 signature>"
}

Сервис восстанавливает сообщение challenge, проверяет подпись Ed25519 и сохраняет кошелёк. Каждый nonce может быть использован только один раз; повторные запросы отклоняются.

Возвращает { "pubkey": "<base58>", "created_at": "<iso8601>" }.

GET /auth/wallets

Получить список всех верифицированных кошельков аутентифицированного пользователя. Требуется действительный JWT.

DELETE /auth/wallets/{pubkey}

Удалить верифицированный кошелёк из аккаунта аутентифицированного пользователя. Требуется действительный JWT.

GET /health

Проверка работоспособности. Возвращает 200 ok. Аутентификация не требуется.

Структура JWT

Токены используют алгоритм HS256 и истекают через 24 часа после выдачи.

ClaimЗначение
subUUID пользователя
role"user" или "operator"
iss"private-channel-auth"
aud"private-channel-gateway"
expUnix timestamp (24ч с момента выдачи)

iss и aud присутствуют в payload JWT, но проверяются JWT-конфигурацией шлюза, а не десериализуются в структуру claims приложения. Код на уровне приложения имеет доступ только к sub, role и exp.

Передайте токен в заголовке Authorization:

Authorization: Bearer <JWT_TOKEN>

Роли

user

Роль по умолчанию при регистрации.

  • Доступ ограничен верифицированными кошельками самого пользователя
  • Заблокированы: getBlock, getTransaction, simulateTransaction
  • Доступно: вызов Deposit в Escrow Program, инициирование вывода средств через WithdrawFunds

operator

Привилегированная роль. Назначается только вручную; самостоятельного способа повысить роль с user до operator не существует.

Выдайте роль через Admin CLI (private-channel-auth-admin):

private-channel-auth-admin set-role --username alice --role operator

или с помощью прямого SQL-запроса:

Это привилегированная операция с базой данных. Ограничьте доступ к базе данных Auth Service соответствующим образом и ведите аудит всех изменений ролей.

UPDATE private_channel_auth.users SET role = 'operator' WHERE username = 'alice';

Зарегистрировать кошелёк без процедуры самостоятельной верификации (Admin CLI, private-channel-auth-admin):

private-channel-auth-admin attach-wallet --username alice --pubkey <base58-pubkey>

Это вставляет верифицированный кошелёк напрямую в таблицу verified_wallets, минуя процедуру challenge/verify. Применяется ограничение уникальности по (user_id, pubkey). Сама по себе эта команда не выдаёт роль operator — для этого используйте set-role или приведённый выше SQL-запрос. Команда предназначена для привязки кошелька к аккаунту (например, сервисному) без прохождения интерактивной процедуры challenge/verify.

Возможности:

  • Обходит все проверки владения кошельком
  • Полный доступ ко всем RPC-методам шлюза, включая getBlock, getTransaction, simulateTransaction
  • Обязательно для: ReleaseFunds, ResetSmtRoot

Полный процесс аутентификации

Выполнение аутентифицированных запросов

const response = await fetch("http://localhost:8899/", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${jwtToken}`
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getBalance",
params: [walletAddress]
})
});
const data = await response.json();

Эндпоинты шлюза

Следующие эндпоинты не требуют аутентификации:

ЭндпоинтМетодОписаниеУспехОшибка
/healthGETПроверка работоспособности200 {"status":"ok"}-
/readyGETГлубокая проверка готовности; опрашивает узлы записи и чтения200 {"status":"ready"}503 {"status":"degraded"}

Справочник по JWT_SECRET и переменным окружения шлюза см. в справочнике по конфигурации.

Матрица доступа к RPC-методам

Следующие методы распознаются шлюзом. Если JWT_SECRET задан, доступ зависит от роли в JWT:

МетодМаршрутБез JWTuseroperator
sendTransactionУзел записи✓✓✓
getLatestBlockhashУзел чтения✓✓✓
getSlotУзел чтения✓✓✓
getRecentBlockhashУзел чтения✓✓✓
getSignatureStatusesУзел чтения✓✓✓
getTransactionCountУзел чтения✓✓✓
getFirstAvailableBlockУзел чтения✓✓✓
getBlocksУзел чтения✓✓✓
getEpochInfoУзел чтения✓✓✓
getEpochScheduleУзел чтения✓✓✓
getRecentPerformanceSamplesУзел чтения✓✓✓
getBlockTimeУзел чтения✓✓✓
getVoteAccountsУзел чтения✓✓✓
getSupplyУзел чтения✓✓✓
getSlotLeadersУзел чтения✓✓✓
isBlockhashValidУзел чтения✓✓✓
getAccountInfoУзел чтения401ownership-gated¹✓
getTokenAccountBalanceУзел чтения401ownership-gated¹✓
getSignaturesForAddressУзел чтения401ownership-gated¹✓
getBlockУзел чтения401403✓
getTransactionУзел чтения401403✓
simulateTransactionУзел чтения401403✓

¹ Ownership-gated: для SPL Token account (поле owner равно TokenkegQ... или TokenzQ..., данные не менее 165 байт) шлюз проверяет, совпадает ли поле owner или delegate с одним из верифицированных кошельков аутентифицированного пользователя. Для любого другого типа аккаунта (кошелёк System Program или неизвестный PDA) вместо этого проверяется, является ли запрашиваемый pubkey одним из верифицированных кошельков пользователя — поскольку у таких аккаунтов нет поля owner/delegate для проверки. Если любая из проверок не проходит, возвращается 403.

Is this page helpful?