%%{init: {
'theme': 'base',
'er': {
'useMaxWidth': false
},
'themeVariables': {
'mainBkg': '#FFF9C4',
'lineColor': '#2C3E50',
'borderClassName': '#FBC02D',
'nodeBorder': '#FBC02D',
'attributeBackend': '#FFF9C4'
}
}}%%
erDiagram
users_postgres {
int64 id PK
varchar email UK
varchar password_hash
varchar user_type
uuid group_id
boolean is_active
timestamp created_at
timestamp updated_at
}
sessions_redis {
string key_token_uuid PK
int64 user_id
}
users_postgres ||--o{ sessions_redis : "has active"
Microservice: Базовый авторизационный сервис, токен доступа, токен обновления
Спецификация gRPC-интерфейсов, логики авторизации и архитектуры хранения данных
В открытом доступе представлена демонстрационная версия метода. В настоящей публичной документации отображены не все шаги, технические сценарии и приватные эндпоинты для системы цифровых симуляторов бизнес-процессов.
- Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence).
1 Общее назначение и архитектурная роль сервиса
Базовый микросервис Auth-Service выполняет функции единого центра аутентификации, ведения активных сессий и авторизации межсервисных запросов в системе. Компонент реализован как gRPC-сервер на языке Go.
1.1 Ключевые архитектурные решения:
- Оптимизация межсервисного взаимодействия: Идентификатор группы пользователя (group_id), к которой он привязан, извлекается при авторизации и вшивается в MapClaims JWT-токена подписи HMAC-SHA256. Это исключает необходимость для смежных доменных воркеров выполнять повторные SQL-запросы в базу авторизации — они получают контекст группы напрямую из валидированной структуры токена.
- Сквозная трассировка (Distributed Tracing): Транспортный слой оснащен перехватчиком UnaryServerInterceptor, который автоматически проверяет наличие заголовка x-request-id в gRPC-метаданных. Если клиент или прокси-сервер не передали маркер, интерцептор генерирует UUID v4, регистрирует его в контексте и обогащает им каждую строку структурированного JSON-лога в os.Stdout.
2 Структура и конфигурация слоя баз данных (Реестр СУБД)
Компонент инициализации инфраструктуры DB обеспечивает параллельное подключение к реляционному пулу PostgreSQL и кэш-слою Redis с обязательным синхронным вызовом процедуры Ping() при старте.
2.1 Конфигурация пула соединений PostgreSQL (pgx/v5)
Для минимизации накладных расходов на сетевые транзакции используется пул соединений драйвера pgxpool. Настройки пула зафиксированы в коде: * MaxConns — Максимальный лимит одновременно открытых сессий пула равен 25. * MinConns — Минимальное количество гарантированно удерживаемых коннектов равно 5. * MaxConnLifetime — Предельный жизненный цикл сетевого соединения составляет 30 минут, после чего оно переоткрывается.
2.2 Конфигурация сессионного кэша Redis (go-redis/v9)
Репозиторий SessionRepository изолирует хранение временных долгоживущих токенов в оперативной памяти Redis на логическом секторе DB 0. Ключи формируются по маске refresh:UUID_ТОКЕНА со строгим ограничением времени жизни (TTL), равным 30 дням (30 * 24 * Hour). При выходе из системы или ротации ключей запись атомарно уничтожается методом DeleteSession.
2.3 ER-диаграмма базы данных (Связи сущностей)
3 Спецификация gRPC-интерфейсов (Транспортный контракт)
Сервер обрабатывает данные в рамках спецификации AuthServiceServer, преобразуя внутренние исключения репозиториев в канонические коды ошибок google.golang.org/grpc/codes.
3.1 Метод ValidateToken (Авторизация токена доступа)
Вызывается шлюзами интеграции для подтверждения прав клиента.
- Входные параметры (pb.ValidateRequest): Строковое поле access_token. При пустом значении сервер возвращает статус codes.InvalidArgument.
- Выходные параметры (pb.ValidateResponse): Логический флаг is_valid, числовой идентификатор пользователя user_id, строковые метки типа аккаунта user_type (Строго фиксированные доменные константы: REAL или DIGITAL) и UUID-строка group_id. При невалидной криптографической подписи или истечении срока действия токена отдается статус codes.Unauthenticated.
4 Сценарий взаимодействия при валидации сессии (Sequence Diagram)
Ниже представлена диаграмма обработки запроса верификации токена, разбора метаданных трассировки и логического маппинга параметров группы.
%%{init: {
'theme': 'base',
'themeVariables': {
'actorBkg': '#E3F2FD',
'actorBorder': '#546E7A',
'actorTextColor': '#0D47A1',
'rectBkg': '#FFF9C4',
'rectBorder': '#FBC02D',
'noteBkgColor': '#F3E5F5',
'noteBorderColor': '#7E57C2',
'noteTextColor': '#311B92',
'signalColor': '#2C3E50',
'signalLineColor': '#2C3E50'
}
}}%%
sequenceDiagram
autonumber
actor Client as Внешний gRPC Компонент
participant Interceptor as LoggingInterceptor (Go)
participant Server as GRPCServer Transport
participant UR as UserRepository (Postgres)
Client->>Interceptor: Вызов метода gRPC ValidateToken с MD [x-request-id]
activate Interceptor
note over Interceptor: Шаг 2: Извлечение x-request-id из метаданных.<br/>При отсутствии — генерация uuid.New().String()
note over Interceptor: Шаг 3: Инициализация JSON-логгера slog с фиксацией request_id
Interceptor->>Server: Перенаправление запроса во внутренний транспортный хэндлер
activate Server
Server->>UR: Вызов репозитория пользователей по ID из токена GetByID(id)
activate UR
UR-->>Server: Возврат User (ID, UserType, IsActive, GroupID)
deactivate UR
note over Server: Шаг 7: Проверка активности IsActive и маппинг GroupID в наружное поле GroupId
Server-->>Interceptor: Проброс protobuf-структуры ValidateResponse и статуса ошибки
deactivate Server
note over Interceptor: Шаг 9: Расчет duration_ms и запись лога JSON Lines в os.Stdout
Interceptor-->>Client: Ответ ValidateResponse + gRPC Status Code
deactivate Interceptor
4.1 Таблица расшифровки шагов сценария ValidateToken
| Шаг | Действие | Параметры / Запросы / DTO | Код ошибки (canonical_code) |
HTTP / gRPC статус |
|---|---|---|---|---|
1 (Client -> Interceptor) |
Смежный микросервис выполняет вызов метода проверки сессии, передавая маркер трассировки в метаданных gRPC. | gRPC Metadata Context:x-request-id: "uuid-v4-trace-id" |
AUTH_INVALID_ARGUMENT | codes.InvalidArgument (400) |
2 (Interceptor -> Interceptor) |
Внутренняя логика: Интерцептор извлекает маркер из контекста. При его отсутствии генерирует новый UUID и регистрирует его в контексте под ключом RequestIDKey. | Внутренняя функция:getOrCreateRequestID(ctx) |
Нет | codes.OK (200) |
3 (Interceptor -> Interceptor) |
Внутренняя логика: В поток os.Stdout сбрасывается JSON-лог о начале обработки запроса с привязанным идентификатором трассировки. |
slog JSON Line Payload:{ "msg": "gRPC request started", "request_id": "uuid", "method": "/pb.AuthService/ValidateToken" } |
Нет | codes.OK (200) |
4 (Interceptor -> Server) |
Интерцептор передает управление на транспортный слой gRPC-сервера, пробрасывая модифицированный контекст. | Внутренний вызов Go:handler(ctx, req) |
Нет | codes.OK (200) |
5 (Server -> UR) |
Сервис проверяет подпись входящего токена через jwt.Parse и выполняет запрос к репозиторию для извлечения актуальной карточки по ID. | Внутренний метод репозитория:r.pool.QueryRow(ctx, query, id).Scan(...) |
DB_CONNECTION_FAILURE | codes.Internal (500) |
6 (UR -> Server) |
Репозиторий перехватывает ошибку отсутствия строк pgx.ErrNoRows, трансформирует ее в доменное исключение и возвращает данные. | SQL Response: Кортеж полей ( id, email, password_hash, user_type, is_active, group_id) |
AUTH_USER_NOT_FOUND | codes.Unauthenticated (401) |
7 (Server -> Server) |
Внутренняя логика: Транспортный слой проверяет флаг блокировки аккаунта user.IsActive и осуществляет финальный маппинг данных в структуру ответа. | Protobuf Response Message:pb.ValidateResponse{GroupId: groupID, IsValid: true} |
AUTH_ACCOUNT_SUSPENDED | codes.Unauthenticated (401) |
8 (Server -> Interceptor) |
gRPC-сервер возвращает сформированный protobuf-ответ обратно в слой интерцептора логирования. | gRPC Internal Response | Нет | codes.OK (200) |
9 (Interceptor -> Interceptor) |
Внутренняя логика: Фиксация общего времени обработки запроса. Запись итогового лога в JSON-формате в stdout. |
slog JSON Line Payload:{ "level": "INFO", "duration_ms": 11.4, "request_id": "trace-id" } |
CRYPTO_SIGNING_ERROR | codes.Internal (500) |
10 (Interceptor -> Client) |
Финальный ответ со статусом проверки и идентификатором группы группы уходит вызывающей доменной системе. | gRPC Wire Response DTO:ValidateResponse{is_valid: true, group_id: "uuid"} |
Нет | codes.OK (200) |
5 Справочник Обсервабилити (Структура логов slog для ClickHouse)
Каждое событие, проходящее через интерцептор, пишется в os.Stdout в виде плоской JSON-строки. При обработке ошибок Vector отправляет в ClickHouse следующий набор канонических полей:
| 1. Код (canonical_code) | 2. Уровень (log_level) | 3. Статусы (transport_statuses) | 4. Получатель (error_target) | 5. JSON для Фронтенда (ui_payload) | 6. Метрики для ClickHouse (observability_json) |
|---|---|---|---|---|---|
| AUTH_INVALID_ARGUMENT | WARN | {“grpc”: 3, “http”: 400} | EXTERNAL_SYSTEM | null | {“metric”: “validation_fail”, “labels”: {“reason”: “missing_token_or_email”}} |
| AUTH_TOKEN_EXPIRED | WARN | {“grpc”: 16, “http”: 401} | EXTERNAL_SYSTEM | null | {“metric”: “auth_fail”, “labels”: {“reason”: “invalid_token_signature_or_expired”}} |
| AUTH_ACCOUNT_SUSPENDED | WARN | {“grpc”: 7, “http”: 403} | EXTERNAL_SYSTEM | null | {“metric”: “login_blocked”, “labels”: {“reason”: “user_is_blocked”}} |
| DB_CONNECTION_FAILURE | ERROR | {“grpc”: 13, “http”: 500} | INTERNAL_SYSTEM | null | {“metric”: “db_pool_error”, “labels”: {“service”: “auth_service”}} |