%%{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 / Swagger Enterprise).
1 Начало
Создадим базовый авторизационный сервис пользователей (реальных и “цифровых”) для полученния доступа к эндпоинтам приложения. Методы сервиса будут синхронными и будут предоставлять возможность: регистрации, авторизации и выхода из приложения. И дополнительные методы ваоидации и обновления токена.
1.1 1. Общее назначение и архитектурная роль сервиса
Микросервис Auth-Service выполняет функции единого центра аутентификации, ведения активных сессий и авторизации межсервисных запросов в системе. Компонент реализован как высокопроизводительный gRPC-сервер на языке Go.
1.1.1 Ключевые архитектурные решения:
- Оптимизация межсервисного взаимодействия: Идентификатор группы пользователя (group_id), к которой он привязан, извлекается при авторизации и вшивается в криптографическое клеймо MapClaims JWT-токена подписи HMAC-SHA256. Это исключает необходимость для смежных доменных воркеров выполнять повторные SQL-запросы в базу авторизации — они получают контекст группы напрямую из валидированной структуры токена.
- Сквозная трассировка (Distributed Tracing): Транспортный слой оснащен перехватчиком UnaryServerInterceptor, который автоматически проверяет наличие заголовка x-request-id в gRPC-метаданных. Если клиент или прокси-сервер не передали маркер, интерцептор генерирует UUID v4, регистрирует его в контексте и обогащает им каждую строку структурированного JSON-лога в os.Stdout.
1.2 2. Структура и конфигурация слоя баз данных (Реестр СУБД)
Компонент инициализации инфраструктуры DB обеспечивает параллельное подключение к реляционному пулу PostgreSQL и кэш-слою Redis с обязательным синхронным вызовом процедуры Ping() при старте.
1.2.1 2.1. Конфигурация пула соединений PostgreSQL (pgx/v5)
Для минимизации накладных расходов на сетевые транзакции используется пул соединений драйвера pgxpool. Настройки пула зафиксированы в коде: * MaxConns — Максимальный лимит одновременно открытых сессий пула равен 25. * MinConns — Минимальное количество гарантированно удерживаемых коннектов равно 5. * MaxConnLifetime — Предельный жизненный цикл сетевого соединения составляет 30 минут, после чего оно мягко переоткрывается.
1.2.2 2.2. Конфигурация сессионного кэша Redis (go-redis/v9)
Репозиторий SessionRepository изолирует хранение временных долгоживущих токенов в оперативной памяти Redis на логическом секторе DB 0. Ключи формируются по маске refresh:UUID_ТОКЕНА со строгим ограничением времени жизни (TTL), равным 30 дням (30 * 24 * Hour). При выходе из системы или ротации ключей запись атомарно уничтожается методом DeleteSession.
1.2.3 2.3. ER-диаграмма базы данных (Связи сущностей)
1.3 3. Спецификация gRPC-интерфейсов (Транспортный контракт)
Сервер обрабатывает данные в рамках спецификации AuthServiceServer, преобразуя внутренние исключения репозиториев в канонические коды ошибок google.golang.org/grpc/codes.
1.3.1 3.1. Метод ValidateToken (Авторизация токена доступа)
Вызывается шлюзами интеграции для подтверждения прав клиента.
- Входные параметры (pb.ValidateRequest): Строковое поле access_token. При пустом значении сервер возвращает статус codes.InvalidArgument.
- Выходные параметры (pb.ValidateResponse): Логический флаг is_valid, числовой идентификатор пользователя user_id, строковые метки типа аккаунта user_type (Строго фиксированные доменные константы: REAL или DIGITAL) и UUID-строка group_id. При невалидной криптографической подписи или истечении срока действия токена отдается статус codes.Unauthenticated.
1.4 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
1.4.1 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) |
1.5 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”}} |