Манитон Docs

Auth Service

Сервис аутентификации, KYC и комплаенс

Auth Service

Auth Service — это центральный сервис платформы, отвечающий за управление идентичностью пользователей, KYC-проверки, контроль лимитов и санкционные проверки.

Обзор

Сервис обеспечивает:

  • Аутентификацию и авторизацию пользователей
  • KYC-процессы (Know Your Customer)
  • Контроль лимитов операций
  • Санкционные проверки по спискам
  • Управление ролями и разрешениями

Архитектура

Доменные области

auth-service/
├── domains/
│   ├── authz/           # Авторизация (JWT, RBAC)
│   │   ├── application/
│   │   │   └── use-cases/
│   │   │       ├── validate-token.use-case.ts
│   │   │       └── check-permissions.use-case.ts
│   │   └── infrastructure/
│   │       └── better-auth/
│   └── identity/        # Идентификация и KYC
│       ├── application/
│       │   └── use-cases/
│       │       ├── get-user-profile.use-case.ts
│       │       ├── submit-kyc.use-case.ts
│       │       ├── review-kyc.use-case.ts
│       │       ├── check-limits.use-case.ts
│       │       ├── check-sanctions.use-case.ts
│       │       ├── block-user.use-case.ts
│       │       └── unblock-user.use-case.ts
│       └── infrastructure/
│           └── sanctions/
└── infrastructure/
    ├── db/              # PostgreSQL
    ├── kafka/           # Kafka events
    └── audit/           # Audit logging

API (gRPC Connect)

IdentityService

GetUserProfile

Получение профиля пользователя.

message GetUserProfileRequest {
  RequestContext context = 1;
  string user_id = 2;
}

message GetUserProfileResponse {
  UserProfile profile = 1;
}

Пример:

const response = await identityClient.getUserProfile(
  { requestId, correlationId, idempotencyKey },
  userId
);

SubmitKyc

Отправка KYC-заявки на проверку.

message SubmitKycRequest {
  RequestContext context = 1;
  SubmitKycPayload payload = 2;
}

message SubmitKycPayload {
  string user_id = 1;
  string full_name = 2;
  string citizenship = 3;
  Address address = 4;
  repeated DocumentReference documents = 5;
  string date_of_birth = 6;
  string passport_number = 7;
}

Процесс:

  1. Пользователь загружает документы (паспорт, селфи)
  2. Данные отправляются в СМЭВ для верификации
  3. Создается KYC case со статусом OPEN
  4. Оператор проверяет и утверждает/отклоняет

ReviewKyc

Рассмотрение KYC-заявки оператором.

message ReviewKycRequest {
  RequestContext context = 1;
  string case_id = 2;
  KycCaseStatus status = 3;  // APPROVED, REJECTED, BLOCKED
  string reason = 4;
  KycStatus target_kyc_level = 5;  // BASIC, STANDARD, ADVANCED
}

Статусы KYC case:

  • OPEN — заявка создана
  • IN_REVIEW — на рассмотрении
  • APPROVED — одобрено
  • REJECTED — отклонено
  • BLOCKED — заблокировано

CheckLimits

Проверка лимитов перед операцией.

message CheckLimitsRequest {
  RequestContext context = 1;
  string user_id = 2;
  LimitType limit_type = 3;  // DEPOSIT, WITHDRAWAL, TRADING
  Money amount = 4;
  OperationType operation_type = 5;
}

message CheckLimitsResponse {
  bool allowed = 1;
  string reason = 2;
}

Типы лимитов:

  • DEPOSIT — лимит на ввод средств
  • WITHDRAWAL — лимит на вывод средств
  • EXTERNAL — лимит на внешние операции
  • TRADING — лимит на торговлю

Периоды:

  • DAILY — дневной
  • WEEKLY — недельный
  • MONTHLY — месячный

CheckSanctions

Проверка пользователя по санкционным спискам.

message CheckSanctionsRequest {
  RequestContext context = 1;
  string user_id = 2;
  SubmitKycPayload payload = 3;
}

message CheckSanctionsResponse {
  SanctionsCheck check = 1;
}

Процесс:

  1. Проверка по спискам OFAC, EU, UN
  2. Проверка по российским спискам
  3. Проверка PEP (Politically Exposed Persons)
  4. Возврат статуса и совпадений

BlockUser / UnblockUser

Блокировка и разблокировка пользователя.

message BlockUserRequest {
  RequestContext context = 1;
  string user_id = 2;
  string reason = 3;
}

AuthZService

ValidateToken

Валидация JWT токена.

message ValidateTokenRequest {
  string access_token = 1;
}

message ValidateTokenResponse {
  bool valid = 1;
  string user_id = 2;
  repeated string roles = 3;
  repeated string scopes = 4;
}

CheckPermissions

Проверка прав доступа.

message CheckPermissionsRequest {
  string user_id = 1;
  string resource = 2;
  repeated string required_roles = 3;
  repeated string required_scopes = 4;
}

События Kafka

Identity Events

Топик: maniton.identity.events.v1

UserCreatedEvent

message UserCreatedEvent {
  RequestContext context = 1;
  string user_id = 2;
  string email = 3;
  string phone = 4;
}

KycStatusChangedEvent

message KycStatusChangedEvent {
  RequestContext context = 1;
  string user_id = 2;
  KycStatus old_status = 3;
  KycStatus new_status = 4;
}

UserBlockedEvent

message UserBlockedEvent {
  RequestContext context = 1;
  string user_id = 2;
  string reason = 3;
}

Use Cases

GetUserProfileUseCase

Получение профиля пользователя с фильтрацией по KYC статусу.

async execute(userId: string): Promise<UserProfile> {
  const profile = await this.userRepository.findById(userId);
  
  if (!profile) {
    throw new NotFoundException('User not found');
  }
  
  return this.mapper.toProto(profile);
}

SubmitKycUseCase

Создание KYC case и отправка на проверку.

async execute(
  context: RequestContext,
  payload: SubmitKycPayload
): Promise<KycCase> {
  // 1. Валидация данных
  this.validatePayload(payload);
  
  // 2. Создание KYC case
  const kycCase = new KycCase(
    crypto.randomUUID(),
    payload.userId,
    KycCaseStatus.OPEN,
    RiskLevel.LOW,
    payload
  );
  
  // 3. Отправка в СМЭВ
  await this.smevClient.verify(payload);
  
  // 4. Сохранение
  await this.kycCaseRepository.save(kycCase);
  
  // 5. Публикация события
  await this.eventPublisher.publish({
    type: 'KycSubmitted',
    payload: kycCase,
  });
  
  return kycCase;
}

CheckLimitsUseCase

Проверка лимитов с учетом периода и типа операции.

async execute(
  context: RequestContext,
  userId: string,
  limitType: LimitType,
  amount: Money,
  operationType: OperationType
): Promise<{ allowed: boolean; reason?: string }> {
  // 1. Получение лимитов пользователя
  const limits = await this.limitRepository.findByUserAndType(userId, limitType);
  
  // 2. Проверка каждого периода
  for (const limit of limits) {
    const used = await this.getUsedAmount(userId, limit.period, operationType);
    const total = used + amount.amount.value;
    
    if (BigInt(total) > BigInt(limit.maxAmount.amount.value)) {
      return {
        allowed: false,
        reason: `Limit exceeded for ${limit.period}: ${total} > ${limit.maxAmount.amount.value}`,
      };
    }
  }
  
  return { allowed: true };
}

Безопасность

JWT Токены

  • Access Token: 15 минут
  • Refresh Token: 30 дней
  • Алгоритм: RS256 (RSA Signature with SHA-256)
  • Ключи: Хранятся в HSM

RBAC

Роли:

  • USER — обычный пользователь
  • ADMIN — администратор
  • OPERATOR — оператор KYC
  • AUDITOR — аудитор

Разрешения:

  • KYC_APPROVE — одобрение KYC
  • KYC_REJECT — отклонение KYC
  • USERS_BLOCK — блокировка пользователей
  • USERS_UNBLOCK — разблокировка пользователей
  • LIMITS_VIEW — просмотр лимитов
  • LIMITS_EDIT — редактирование лимитов

Санкционные проверки

Источники:

  • OFAC (США)
  • EU Sanctions (Евросоюз)
  • UN Sanctions (ООН)
  • Российские списки (ФСФН, ЦБ РФ)

Алгоритм:

  1. Нормализация данных (ФИО, дата рождения)
  2. Фаззи-матчинг (Levenshtein distance)
  3. Проверка PEP
  4. Проверка связей (семья, партнеры)

Интеграции

СМЭВ (Система Межведомственного Электронного Взаимодействия)

Проверка паспортных данных и документов через государственные сервисы.

interface SmevClient {
  verifyPassport(passportNumber: string): Promise<PassportInfo>;
  verifyInn(inn: string): Promise<InnInfo>;
  verifySnils(snils: string): Promise<SnilsInfo>;
}

Better Auth

Интеграция с Better Auth для аутентификации.

import { auth } from '@infrastructure/better-auth/better-auth.config';

export const authConfig = auth({
  providers: [
    {
      id: 'phone',
      name: 'Phone',
      type: 'credential',
    },
  ],
  session: {
    expiresIn: 15 * 60, // 15 минут
  },
});

Мониторинг

Метрики

  • auth_requests_total — общее количество запросов
  • auth_requests_duration_seconds — время обработки
  • kyc_checks_total — количество KYC проверок
  • kyc_checks_duration_seconds — время KYC проверки
  • limits_checks_total — количество проверок лимитов
  • sanctions_checks_total — количество санкционных проверок

Логи

this.logger.log('KYC submitted', {
  userId: payload.userId,
  caseId: kycCase.caseId,
  riskLevel: kycCase.riskLevel,
});

Тестирование

# Unit тесты
bun test --filter auth-service

# Интеграционные тесты
bun test:integration --filter auth-service

# E2E тесты
cd apps/tests/playwright
bun run test --grep "Auth"

Troubleshooting

Проблема: KYC проверка зависает

Решение: Проверьте соединение с СМЭВ API.

# Проверка доступности СМЭВ
curl https://smev.gosuslugi.ru/portal/api

Проблема: Лимиты не работают

Решение: Проверьте конфигурацию лимитов в базе данных.

SELECT * FROM user_limits WHERE user_id = '<user-id>';

Проблема: Санкционные проверки медленные

Решение: Добавьте кэширование результатов.

const cached = await this.cache.get(`sanctions:${userId}`);
if (cached) return cached;

Дополнительные ресурсы

On this page