AIDeskLab.AuthClient 1.1.7
AIDeskLab.AuthClient
Клиентская библиотека NuGet для интеграции сервисов экосистемы AIDeskLab с центральным сервером аутентификации/авторизации AuthServer через gRPC.
Целевой framework: .NET 8.0. Распространяется как пакет
AIDeskLab.AuthClient.
Этот документ — единая точка входа для AI‑агентов и разработчиков команд AIDeskLab при подключении пакета. Все примеры соответствуют актуальному публичному API библиотеки.
Содержание
- Возможности
- Установка
- Быстрый старт
- Конфигурация
- Регистрация в DI
- Карта сервисов
- Аутентификация и токены
- Регистрация пользователей
- Управление ролями и разрешениями
- Управление организационной структурой
- Управление сервисами и модулями
- Контрагенты
- Логирование и аналитика
- Telegram интеграция
- Middleware для ASP.NET Core
- Межсервисная авторизация (Service-to-Service)
- Хранение токенов
- Обработка ошибок
- Best Practices
- Совместимость и версионирование
- Лицензия и ссылки
Возможности
Аутентификация и авторизация
- Логин пользователей по логину/паролю, Telegram, телефону + Telegram, API‑ключам сервисов.
- Двухфакторная аутентификация (2FA) с завершением через
CompleteTwoFactorAuthAsync. - Refresh access/refresh токенов (включая отдельный
RefreshServiceTokenAsyncдля S2S). - Runtime‑валидация JWT, проверка прав через
ITokenValidationService.
Регистрация
- Универсальная воронка заявок: Telegram, Web, Mobile, API.
- Workflow одобрения/отклонения, верификация email, просмотр статусов.
Управление пользователями и оргструктурой
- Пользователи, профили, Telegram аккаунты.
- Системные и организационные роли, разрешения.
- Организации (иерархия, 2FA политики), отделы, должности, сотрудники, рабочие команды, физические лица.
- Назначения пользователей (
UserAssignment).
Управление сервисами
- Регистрация и сопровождение сервисов, выпуск API‑ключей.
- Модули сервисов и связи модуль ⇄ сервис.
- Межсервисные разрешения (
ServiceToServicePermission) и пользователи, доступные сервису.
Контрагенты
- CRUD контрагентов и контактов, юрисдикционные данные, миграция контактов в Person.
Логи и аналитика
- Доступ к логам по пользователям/сервисам, статистика, топ активности, статистика ошибок.
Инфраструктура
- gRPC поверх
Grpc.Net.Client(HTTP/2, опционально SSL/TLS). - AutoMapper для маппинга proto ↔ модели (валидация конфигурации в DEBUG).
- Хранилища токенов:
InMemory,File,Custom(SystemKeyStoreзарезервирован). - Авто‑refresh, политики повторов (Fixed/Linear/ExponentialBackoff с jitter).
- Прозрачная межсервисная авторизация:
DelegatingHandlerподключается ко всемHttpClientи middleware валидации входящих S2S запросов с локальнымMemoryCache. - Отдельный middleware валидации JWT для классических Web API.
Установка
dotnet add package AIDeskLab.AuthClient
Через Package Manager Console:
Install-Package AIDeskLab.AuthClient
Зависимости пакета (ключевые): Grpc.Net.Client, Google.Protobuf, AIDesk.AuthServer.Contracts, Microsoft.AspNetCore.Authentication.JwtBearer, Microsoft.Extensions.Caching.Memory, AutoMapper.
Поддерживаемые ОС: Windows / macOS / Linux (для условной компиляции определены символы WINDOWS, MACOS, LINUX).
Быстрый старт
1. ASP.NET Core (Web API)
using AuthClient.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddAuthClient(builder.Configuration);
var app = builder.Build();
app.UseAuthClient();
app.UseAuthorization();
app.MapControllers();
app.Run();
UseAuthClient() подключает middleware межсервисной авторизации (ServiceToServiceAuthMiddleware). Если ваш сервис принимает входящие S2S вызовы — вызов обязателен.
Минимальная регистрация без IConfiguration:
builder.Services.AddAuthClient("https://auth-server.example.com", "my-service-id");
Регистрация через делегат:
builder.Services.AddAuthClient(options =>
{
options.ServerUrl = "https://auth-server.example.com";
options.ServiceId = "my-service-id";
options.ApiKey = builder.Configuration["AuthClient:ApiKey"];
options.ApiSecret = builder.Configuration["AuthClient:ApiSecret"];
options.EnableServiceToServiceAuth = true;
});
2. Generic Host / Worker / Console (non‑web)
UseAuthClient() к IApplicationBuilder относится только к ASP.NET Core. В non‑web хостах используйте сервисы напрямую через DI:
using AuthClient.Extensions;
using AuthClient.Services.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddAuthClient(context.Configuration);
services.AddHostedService<PermissionProbeWorker>();
})
.Build();
await host.RunAsync();
public sealed class PermissionProbeWorker : BackgroundService
{
private readonly ITokenValidationService _tokenValidation;
public PermissionProbeWorker(ITokenValidationService tokenValidation)
=> _tokenValidation = tokenValidation;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var check = await _tokenValidation.CheckPermissionAsync(
userId: "user-id",
serviceId: "my-service-id",
permissionCode: "users.read",
cancellationToken: stoppingToken);
Console.WriteLine($"Permission granted: {check.HasPermission}");
}
}
3. Конфигурация appsettings.json
{
"AuthClient": {
"ServerUrl": "https://auth-server.example.com",
"ServiceId": "my-service-id",
"UseSsl": true,
"OperationTimeout": "00:00:30",
"ApiKey": "service-api-key",
"ApiSecret": "service-api-secret",
"ServiceCode": "my-service",
"EnableServiceToServiceAuth": true,
"LocalCacheExpiry": "00:15:00",
"MaxLocalCacheSize": 10000,
"TokenStorage": {
"StorageType": "InMemory",
"EncryptTokens": true,
"EncryptionKey": "your-encryption-key-at-least-32-chars",
"CacheDuration": "01:00:00"
},
"TokenRefresh": {
"EnableAutoRefresh": true,
"RefreshCheckInterval": "00:01:00",
"RefreshBeforeExpiration": "00:05:00",
"MaxRefreshAttempts": 3,
"RefreshRetryDelay": "00:00:05",
"RefreshOnFirstUse": true
},
"Retry": {
"EnableRetry": true,
"MaxRetryAttempts": 3,
"BaseDelay": "00:00:01",
"MaxDelay": "00:00:30",
"Strategy": "ExponentialBackoff",
"BackoffMultiplier": 2.0,
"UseJitter": true,
"MaxJitterPercent": 20
}
}
}
Секреты (ApiKey, ApiSecret, EncryptionKey) храните в Secret Manager / Key Vault, а не в репозитории.
Конфигурация
AuthClientOptions
Корневые настройки клиента (AuthClient.Configuration.AuthClientOptions).
| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
ServerUrl |
string | Да | — | URL gRPC endpoint AuthServer |
ServiceId |
string | Да | — | ID текущего сервиса (используется как идентификатор в S2S и runtime‑проверках) |
OperationTimeout |
TimeSpan | Нет | 30 сек | Таймаут операций |
UseSsl |
bool | Нет | true | Использовать SSL/TLS для gRPC |
ApiKey |
string? | Нет | null | API‑ключ сервиса для LoginServiceAsync и админ‑операций |
ApiSecret |
string? | Нет | null | API‑секрет сервиса (хранить в секретах) |
ServiceCode |
string? | Нет | null | Код сервиса (используется при авторизации) |
EnableServiceToServiceAuth |
bool | Нет | true | Включить автоматическое добавление S2S заголовков ко всем HttpClient |
LocalCacheExpiry |
TimeSpan | Нет | 15 мин | TTL локального кэша межсервисных проверок |
MaxLocalCacheSize |
int | Нет | 10000 | Лимит записей локального кэша |
TokenStorage |
TokenStorageOptions |
Нет | дефолт | Настройки хранилища токенов |
TokenRefresh |
TokenRefreshOptions |
Нет | дефолт | Настройки авто‑refresh |
Retry |
RetryOptions |
Нет | дефолт | Настройки повторных попыток |
Validate() вызывается автоматически после биндинга и кидает ArgumentException, если ServerUrl/ServiceId пустые или таймаут невалиден.
TokenStorageOptions
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
StorageType |
TokenStorageType |
InMemory |
InMemory / File / SystemKeyStore (TODO) / Custom |
EncryptTokens |
bool | true | Шифровать токены при сохранении |
EncryptionKey |
string | — | Ключ шифрования (≥ 32 символа), обязателен при EncryptTokens=true |
FilePath |
string | — | Путь к файлу для StorageType=File |
KeyPrefix |
string | "AuthClient" | Префикс ключей в системном хранилище (когда будет реализовано) |
CacheDuration |
TimeSpan | 1 час | TTL кэша токенов в памяти |
SystemKeyStore зарезервирован (issue AID‑326) и сейчас бросает NotImplementedException. Для своих реализаций используйте Custom + AddCustomTokenStorage<TStorage>().
TokenRefreshOptions
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
EnableAutoRefresh |
bool | true | Включить автообновление |
RefreshCheckInterval |
TimeSpan | 1 мин | Период фоновой проверки |
RefreshBeforeExpiration |
TimeSpan | 5 мин | За сколько до expiry начинать refresh |
MaxRefreshAttempts |
int | 3 | Макс. попыток |
RefreshRetryDelay |
TimeSpan | 5 сек | Задержка между попытками |
RefreshOnFirstUse |
bool | true | Обновлять при первом использовании, если токен истекает |
RetryOptions
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
EnableRetry |
bool | true | Включить повторы |
MaxRetryAttempts |
int | 3 | Кол‑во попыток |
BaseDelay |
TimeSpan | 1 сек | Базовая задержка |
MaxDelay |
TimeSpan | 30 сек | Максимум задержки |
Strategy |
RetryStrategy |
ExponentialBackoff |
Fixed / Linear / ExponentialBackoff |
BackoffMultiplier |
double | 2.0 | Множитель экспоненты |
UseJitter |
bool | true | Случайный jitter |
MaxJitterPercent |
int | 20 | Макс. % jitter (0..100) |
Регистрация в DI
Доступные расширения IServiceCollection (AuthClient.Extensions.ServiceCollectionExtensions):
services.AddAuthClient(IConfiguration configuration);
services.AddAuthClient(IConfigurationSection section);
services.AddAuthClient(Action<AuthClientOptions> configure);
services.AddAuthClient(string serverUrl, string serviceId);
services.AddCustomTokenStorage<TStorage>(); // своя реализация ITokenStorage
services.ConfigureTokenStorage(opts => { ... }); // post-настройка
services.ConfigureTokenRefresh(opts => { ... });
services.ConfigureRetryPolicy(opts => { ... });
AddAuthClient(...) регистрирует:
IAuthenticationService,IUserRegistrationService,IRegistrationService,IProfileService,ITelegramService;ITokenManagementService,ITokenValidationService,ITokenRefreshService,ITokenStorage;IRoleService,ISystemRoleService,IOrganizationRoleService,IPermissionService,IUserRoleService;IOrganizationService,IUserOrganizationService,IUserAssignmentService,IDepartmentService;IPersonService,IPositionService,IEmployeeService,IWorkTeamService;IServiceManagementService,IServiceUserAccessService,IServiceModuleService;ICounterpartyService,ICounterpartyContactService;IAccessLogService;IServiceToServiceAuthenticationService+ServiceToServiceAuthHandler+CircuitBreakerAuthHandler;- AutoMapper с профилями библиотеки (валидация конфигурации в DEBUG через
AutoMapperValidationService).
HttpClientFactory настраивается так, что CircuitBreakerAuthHandler и ServiceToServiceAuthHandler автоматически добавляются ко всем именованным/типизированным HttpClient. Запросы к самому AuthServer пропускают добавление S2S заголовков, чтобы избежать циклов.
Карта сервисов
| Категория | Интерфейс | Назначение |
|---|---|---|
| Аутентификация | IAuthenticationService |
Логин пользователей и сервисов, refresh, 2FA, S2S batch‑проверка |
| Валидация | ITokenValidationService |
Runtime‑проверка JWT и разрешений |
| Регистрация заявок | IRegistrationService |
Универсальная воронка регистрации (Telegram/Web/Mobile/API) |
| Пользователи | IUserRegistrationService |
CRUD пользователей, активация, поиск |
| Профили | IProfileService |
Полный профиль, Telegram аккаунты |
| Telegram | ITelegramService |
TelegramUser CRUD/листинг |
| Токены | ITokenManagementService |
Активные токены, отзыв, очистка, статистика |
| Старая модель ролей | IRoleService |
Поддерживается для обратной совместимости |
| Системные роли | ISystemRoleService |
Системные роли + разрешения + связь с сервисами |
| Орг. роли | IOrganizationRoleService |
Роли уровня организации |
| Разрешения | IPermissionService |
Реестр permission кодов и связь с ролями |
| Роли пользователей | IUserRoleService |
Назначение ролей, поиск пользователей по роли |
| Организации | IOrganizationService |
Иерархия, 2FA, пользователи организации |
| Связи user↔org | IUserOrganizationService |
Принадлежность к организациям, primary org |
| Назначения | IUserAssignmentService |
Назначения пользователей (должность/роль/служба) |
| Отделы | IDepartmentService |
Иерархия отделов и их пользователи |
| Физлица | IPersonService |
Person сущности и связь с User |
| Должности | IPositionService |
Позиции/должности |
| Сотрудники | IEmployeeService |
Employee = Person × Organization |
| Рабочие команды | IWorkTeamService |
Иерархия рабочих команд |
| Сервисы | IServiceManagementService |
Регистрация сервисов, кредентиалы, S2S разрешения |
| Доступы к сервисам | IServiceUserAccessService |
Кому доступен сервис (через роли) |
| Модули сервисов | IServiceModuleService |
Модули и их связи с сервисами |
| Контрагенты | ICounterpartyService |
CRUD, поиск, юрисдикции |
| Контакты КА | ICounterpartyContactService |
Контакты КА, миграция в Person |
| Логи доступа | IAccessLogService |
Логи и статистика доступа |
| S2S | IServiceToServiceAuthenticationService |
Получение/обновление сервисного токена, валидация входящих S2S |
Все методы возвращают
Task<TResult>, гдеTResultнаследуется отBaseResult(Success,Message,ErrorCode,ErrorDetails). Конкретные результаты (AuthenticationResult,UserInfoResult,OrganizationResult, и т. д.) добавляют типизированные поля (Tokens,User,Organization, …).
Аутентификация и токены
IAuthenticationService — основной вход для пользователей и сервисов.
public interface IAuthenticationService
{
Task<AuthenticationResult> LoginAsync(
string username, string password, string serviceId,
string? organizationId = null, CancellationToken cancellationToken = default);
Task<AuthenticationResult> LoginTelegramAsync(
long telegramId, string serviceId, string? password = null,
string? organizationId = null, TelegramUserInfo? telegramUserInfo = null,
CancellationToken cancellationToken = default);
Task<AuthenticationResult> LoginByTelegramAndPhoneAsync(
long telegramId, string phoneNumber, string serviceId,
string? organizationId = null, CancellationToken cancellationToken = default);
Task<AuthenticationResult> LoginServiceAsync(
string apiKey, string apiSecret, CancellationToken cancellationToken = default);
Task<AuthenticationResult> RefreshTokenAsync(string refreshToken, CancellationToken cancellationToken = default);
Task<AuthenticationResult> RefreshServiceTokenAsync(string refreshToken, CancellationToken cancellationToken = default);
Task<OperationResult> LogoutAsync(string accessToken, CancellationToken cancellationToken = default);
Task<OperationResult> ChangePasswordAsync(
string userId, string currentPassword, string newPassword, string serviceId,
CancellationToken cancellationToken = default);
Task<CompleteTwoFactorResult> CompleteTwoFactorAuthAsync(
string twoFactorSessionId, string verificationCode,
string? organizationId = null, CancellationToken cancellationToken = default);
Task<ServiceAccessValidationResult> ValidateServiceAccessBatchAsync(
string serviceId, List<string> permissionCodes, CancellationToken cancellationToken = default);
}
Пример контроллера:
using AuthClient.Models.Auth;
using AuthClient.Services.Interfaces;
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly IAuthenticationService _auth;
public AuthController(IAuthenticationService auth) => _auth = auth;
[HttpPost("login")]
public async Task<IActionResult> Login(LoginRequestDto request, CancellationToken ct)
{
var result = await _auth.LoginAsync(
request.Username,
request.Password,
serviceId: "my-service-id",
organizationId: request.OrganizationId,
cancellationToken: ct);
if (!result.Success)
return Unauthorized(new { error = result.Message, code = result.ErrorCode });
if (result.Tokens.TwoFactorStatus == TwoFactorStatus.Required)
{
return Ok(new
{
require2Fa = true,
twoFactorSessionId = result.Tokens.TwoFactorSessionId
});
}
return Ok(new
{
accessToken = result.Tokens.AccessToken,
refreshToken = result.Tokens.RefreshToken,
expiresAt = result.Tokens.ExpiresAtDateTime,
userId = result.Tokens.UserId,
serviceId = result.Tokens.ServiceId,
organizationId = result.Tokens.OrganizationId
});
}
}
AuthenticationResult.Tokens (AuthClient.Models.Auth.AuthTokens) содержит:
AccessToken,RefreshToken,ExpiresAt(Unix),ExpiresAtDateTime;UserId,ServiceId,OrganizationId;TwoFactorStatus?,TwoFactorSessionId?;IsExpired,NeedsRefresh(за 5 минут до истечения).
Runtime‑проверка токенов и прав
ITokenValidationService используется в любом потребительском сервисе для проверок без обращения к БД напрямую:
public interface ITokenValidationService
{
Task<TokenValidationResult> ValidateTokenAsync(
string accessToken, string serviceId, CancellationToken cancellationToken = default);
Task<PermissionCheckResult> CheckPermissionAsync(
string userId, string serviceId, string permissionCode,
string? organizationId = null, CancellationToken cancellationToken = default);
Task<UserServicesResult> GetUserAvailableServicesAsync(
string userId, CancellationToken cancellationToken = default);
Task<TokenInfoResult> GetTokenInfoAsync(string tokenId, CancellationToken cancellationToken = default);
}
Глобальная проверка разрешения (без organizationId):
var check = await tokenValidation.CheckPermissionAsync(
userId: userId,
serviceId: "my-service-id",
permissionCode: "users.read",
cancellationToken: ct);
if (!check.HasPermission) return Forbid();
Org‑scoped проверка:
var check = await tokenValidation.CheckPermissionAsync(
userId, "my-service-id", "users.read", organizationId: orgId, cancellationToken: ct);
IPermissionService— это админский сервис управления каталогом разрешений и связями ролей. Для runtime‑проверок типа «является ли пользователь админом» используйтеITokenValidationService.CheckPermissionAsync.
Управление токенами (админ)
ITokenManagementService — административные функции:
GetUserActiveTokensAsync(userId, page, pageSize, ct)GetServiceActiveTokensAsync(serviceId, page, pageSize, ct)RevokeTokenAsync(tokenId, reason, ct)RevokeUserTokensAsync(userId, reason, excludeCurrent = false, ct)RevokeServiceTokensAsync(serviceId, reason, ct)CleanupExpiredTokensAsync(daysOld = 30, dryRun = false, ct)GetTokenStatisticsAsync(startDate?, endDate?, includeDetails = false, ct)
Регистрация пользователей
Универсальная воронка заявок (IRegistrationService)
Поддерживает источники RegistrationSource: Telegram, Web, Mobile, Api.
var registration = await registrationService.SubmitRegistrationAsync(
new RegistrationRequest
{
ServiceId = Guid.Parse("..."),
TelegramId = 123456789,
FirstName = "Иван",
LastName = "Петров",
PhoneNumber = "+79991234567",
LanguageCode = "ru",
Source = RegistrationSource.Telegram,
UserMessage = "Хочу подключиться к боту"
},
serviceId: "my-bot-service-id",
cancellationToken: ct);
if (!registration.Success)
throw new InvalidOperationException(registration.Message);
Полный API:
SubmitRegistrationAsync(request, serviceId, ct)GetRegistrationStatusAsync(telegramId, serviceId, ct)CancelRegistrationAsync(telegramId, serviceId, ct)ListRegistrationRequestsAsync(serviceId, status?, page, pageSize, ct)— праваtelegram.registration.viewApproveRegistrationAsync(approveRequest, serviceId, ct)— праваtelegram.registration.approveRejectRegistrationAsync(requestId, adminComment, serviceId, ct)— праваtelegram.registration.rejectVerifyEmailAsync(email, token, ct)ResendEmailVerificationAsync(email, ct)
Для
SubmitRegistrationAsyncнужна предварительная авторизация сервиса черезLoginServiceAsync(apiKey, apiSecret)— токен подставится автоматически изITokenStorage.
CRUD пользователей (IUserRegistrationService)
RegisterUserAsync(username, email, password, ct)GetUserAsync(userId, ct)GetUserByUsernameAsync(username, ct)UpdateUserAsync(userId, username?, email?, ct)ActivateUserAsync(userId, ct)/DeactivateUserAsync(userId, ct)ListUsersAsync(page, pageSize, search?, ct)
Профили (IProfileService)
GetProfileAsync(userId, ct)→UserProfileResultс полным профилем (PersonProfile, Telegram аккаунты).UpdateProfileAsync(userId, PersonProfile profile, ct)AddTelegramAccountAsync(userId, TelegramAccount account, ct)SetMainTelegramAccountAsync(userId, telegramAccountId, ct)
Управление ролями и разрешениями
Системные роли (ISystemRoleService)
CRUD + 2FA настройки, активация/деактивация, назначение разрешений и связь с сервисами:
CreateSystemRoleAsync, GetSystemRoleAsync, GetSystemRoleByCodeAsync, UpdateSystemRoleAsync, DeleteSystemRoleAsync, ActivateSystemRoleAsync, DeactivateSystemRoleAsync, ListSystemRolesAsync, AssignPermissionToSystemRoleAsync, RemovePermissionFromSystemRoleAsync, GetSystemRolePermissionsAsync, AssignSystemRoleToServiceAsync, RemoveSystemRoleFromServiceAsync.
Орг. роли (IOrganizationRoleService)
CreateOrganizationRoleAsync, GetOrganizationRoleAsync, UpdateOrganizationRoleAsync, DeleteOrganizationRoleAsync, ActivateOrganizationRoleAsync, DeactivateOrganizationRoleAsync, ListOrganizationRolesAsync.
Разрешения (IPermissionService)
CRUD + связи с ролями: CreatePermissionAsync, GetPermissionAsync, UpdatePermissionAsync, DeletePermissionAsync, ListPermissionsAsync, AssignPermissionToRoleAsync, RemovePermissionFromRoleAsync, GetRolePermissionsAsync.
Назначение ролей пользователям (IUserRoleService)
AssignRoleToUserAsync(userId, systemRoleId, serviceId, organizationId?, ct)RemoveRoleFromUserAsync(userId, systemRoleId, serviceId, organizationId?, ct)GetUserRolesAsync(userId, serviceId?, organizationId?, ct)GetUsersByRoleAsync(systemRoleId, page, pageSize, organizationId?, includeInactive, ct)GetUsersByServiceRoleAsync(systemRoleId, serviceId, page, pageSize, organizationId?, includeInactive, ct)
Старый IRoleService
Сохранён для обратной совместимости (плоская модель ролей сервиса). Для нового кода предпочитайте ISystemRoleService / IOrganizationRoleService.
Управление организационной структурой
Организации (IOrganizationService)
CreateOrganizationAsync(code, name, description, parentOrganizationId?, twoFactorEnabled, twoFactorType, ct)GetOrganizationAsync(organizationId, ct)UpdateOrganizationAsync(organizationId, code, name, description, twoFactorEnabled?, twoFactorType?, ct)ActivateOrganizationAsync/DeactivateOrganizationAsync/DeleteOrganizationAsync(forceDelete = false)ListOrganizationsAsync(page, pageSize, parentOrganizationId?, includeInactive, ct)GetChildOrganizationsAsync(parentOrganizationId, includeAllLevels, ct)SetParentOrganizationAsync(organizationId, parentOrganizationId?, ct)GetOrganizationUsersAsync(organizationId, page, pageSize, includeChildOrganizations, ct)
Связи user ↔ org (IUserOrganizationService)
AddUserToOrganizationAsync, RemoveUserFromOrganizationAsync, GetUserOrganizationsAsync, SetUserPrimaryOrganizationAsync, GetUserServiceAccessAsync(userId, serviceId?, organizationId?, ct).
Назначения (IUserAssignmentService)
Управление назначениями пользователей (должность/роль/служба):
CreateUserAssignmentAsync, UpdateUserAssignmentAsync, ArchiveUserAssignmentAsync(reason), DeactivateUserAssignmentAsync, GetUserAssignmentsAsync, GetOrganizationAssignmentsAsync, SetPrimaryAssignmentAsync. Тип задаётся через UserAssignmentType (OrganizationPosition по умолчанию).
Отделы (IDepartmentService)
CRUD + иерархия + пользователи: CreateDepartmentAsync, GetDepartmentAsync, UpdateDepartmentAsync, ActivateDepartmentAsync, DeactivateDepartmentAsync, DeleteDepartmentAsync(forceDelete), ListDepartmentsAsync(organizationId, …), GetChildDepartmentsAsync, GetRootDepartmentsAsync, GetDepartmentHierarchyAsync, GetDepartmentPathAsync, GetDepartmentUsersAsync.
Физические лица (IPersonService)
CreatePersonAsync, GetPersonAsync, GetPersonByUserIdAsync, UpdatePersonAsync, DeletePersonAsync, ListPersonsAsync(page, pageSize, searchText?, ct), SearchPersonsAsync(searchTerm, ct). Поддерживаются Gender, PersonType (Human по умолчанию).
Должности (IPositionService)
CreatePositionAsync, GetPositionAsync, GetPositionByCodeAsync, UpdatePositionAsync, DeletePositionAsync, ListPositionsAsync, GetPositionsByCategoryAsync, GetPositionsByLevelAsync, GetEmployeeCountAsync.
Сотрудники (IEmployeeService)
CreateEmployeeAsync(personId, organizationId, departmentId?, positionId?, hireDate?, employeeNumber?, notes?, ct), GetEmployeeAsync, UpdateEmployeeAsync, TerminateEmployeeAsync(employeeId, reason, terminationDate?, ct), DeleteEmployeeAsync, ListEmployeesAsync, GetEmployeesByOrganizationAsync, GetEmployeesByDepartmentAsync. Поддерживается EmployeeStatus.
Рабочие команды (IWorkTeamService)
CreateWorkTeamAsync, GetWorkTeamAsync, GetWorkTeamByCodeAsync, UpdateWorkTeamAsync, DeleteWorkTeamAsync, ListWorkTeamsAsync, GetWorkTeamsByOrganizationAsync, GetChildWorkTeamsAsync(recursive), GetWorkTeamHierarchyAsync(maxDepth).
Управление сервисами и модулями
Регистрация сервисов (IServiceManagementService)
- CRUD сервисов:
RegisterServiceAsync,GetServiceAsync,UpdateServiceAsync,ActivateServiceAsync,DeactivateServiceAsync,ListServicesAsync. - Кредентиалы:
RegenerateCredentialsAsync(serviceId)→ServiceCredentialsResult(новыеApiKey/ApiSecret). - Разрешения сервиса:
AssignPermissionToServiceAsync,RemovePermissionFromServiceAsync,GetServicePermissionsAsync. - Статистика:
GetServiceUsageStatsAsync(serviceId, startDate?, endDate?, ct). - Service-to-Service permissions:
GrantServiceToServicePermissionAsync(sourceServiceId, targetServiceId, permissionCode, description?, expiryDate?, ct),RevokeServiceToServicePermissionAsync(permissionId),ListServiceToServicePermissionsAsync(sourceServiceId?, targetServiceId?, page, pageSize). - Доступ пользователей:
GetServiceAccessibleUsersAsync,CheckUserAccessToServiceAsync,GetUserServicesAsync.
Доступы (IServiceUserAccessService)
Расширенный API для интеграций: GetServiceAccessibleUsersAsync(serviceId, page, pageSize, systemRoleId?, organizationId?, includeInactive, ct), CheckUserAccessToServiceAsync(userId, serviceId, organizationId?, ct), GetUserServicesAsync(userId, organizationId?, ct).
Модули сервисов (IServiceModuleService)
CRUD модулей и связей модуль ⇄ сервис: CreateServiceModuleAsync, GetServiceModuleAsync, UpdateServiceModuleAsync, DeleteServiceModuleAsync, ActivateServiceModuleAsync, DeactivateServiceModuleAsync, ListServiceModulesAsync, GetServiceModulesByServiceAsync(serviceId, activeOnly), LinkModuleToServiceAsync, UnlinkModuleFromServiceAsync, UpdateServiceModuleLinkAsync, GetServiceModuleLinkAsync, ListServiceModuleLinksAsync.
Контрагенты
Контрагенты (ICounterpartyService)
- CRUD:
CreateCounterpartyAsync,GetCounterpartyAsync(id, includeContacts),UpdateCounterpartyAsync,ActivateCounterpartyAsync,DeactivateCounterpartyAsync,DeleteCounterpartyAsync. - Поиск:
ListCounterpartiesAsync(page, pageSize, activeOnly, jurisdiction?, countryCode?, ct),SearchCounterpartiesAsync(searchTerm, …),GetCounterpartiesByJurisdictionAsync(jurisdiction, …). - Юрисдикционные данные:
GetCounterpartyJurisdictionDataAsync,UpdateCounterpartyJurisdictionDataAsync(taxId, registrationNumber, vatNumber, legalForm, regulatoryAuthority, licenseNumber, registrationDate?, additionalData?, ct).
Контакты КА (ICounterpartyContactService)
CRUD + поиски + миграция в Person: CreateCounterpartyContactAsync, GetCounterpartyContactAsync, UpdateCounterpartyContactAsync, DeleteCounterpartyContactAsync, ListCounterpartyContactsAsync, GetByCounterpartyIdAsync, GetByOrganizationIdAsync, GetByDepartmentIdAsync, GetPrimaryContactAsync, MarkAsOutdatedAsync(contactId, markedByOrganizationId, reason, ct), MigrateToPersonAsync(contactId, personId, ct), GetMigrateableContactsAsync, SetPrimaryContactAsync.
Логирование и аналитика
IAccessLogService — доступ к логам и агрегатам:
GetAccessLogsAsync(page, pageSize, startDate?, endDate?, errorsOnly?, serviceId?, userId?, ct)GetAccessLogsByUserAsync(userId, …),GetAccessLogsByServiceAsync(serviceId, …)GetAccessStatisticsAsync(startDate?, endDate?, serviceId?, userId?, includeHourly, includeDaily, ct)GetTopUsersByActivityAsync(startDate?, endDate?, limit, ct)GetTopServicesByUsageAsync(startDate?, endDate?, limit, ct)GetErrorStatisticsAsync(startDate?, endDate?, serviceId?, topLimit, ct)CleanupOldLogsAsync(daysToKeep = 90, dryRun = false, ct)
Telegram интеграция
ITelegramService работает только с сущностью TelegramUser (не путать с пользователями системы):
GetTelegramUserAsync(telegramId, serviceId, ct)UpdateTelegramUserAsync(UpdateTelegramUserRequest request, serviceId, ct)DeactivateTelegramUserAsync(userId, ct)ListTelegramUsersAsync(isActive?, page, pageSize, ct)
Логин по Telegram реализован в IAuthenticationService.LoginTelegramAsync / LoginByTelegramAndPhoneAsync. Регистрация Telegram‑пользователей — через IRegistrationService.
Middleware для ASP.NET Core
Библиотека предоставляет три middleware (через AuthClient.Extensions и AuthClient.Middleware):
| Метод | Назначение |
|---|---|
app.UseAuthClient() (AuthClient.Extensions) |
Подключает ServiceToServiceAuthMiddleware для прозрачной валидации входящих S2S запросов (заголовки X-Service-Token, X-Request-Id). Рекомендован к использованию во всех ASP.NET Core сервисах AIDeskLab. |
app.UseAuthClient() (AuthClient.Middleware.AuthClientMiddlewareExtensions) |
Подключает AuthClientMiddleware — автоматически достаёт токен из ITokenStorage, обновляет при необходимости, кладёт в HttpContext.Items["AccessToken"]. Подходит для сервисов‑клиентов, которые сами вызывают другие API от имени пользователя. |
app.UseTokenValidation() |
Подключает TokenValidationMiddleware для валидации JWT по TokenValidationOptions (issuer/audience/lifetime/signing key, cookie, query string). |
Для большинства новых сервисов AIDeskLab достаточно вызвать UseAuthClient() из пространства имён AuthClient.Extensions. Если нужно дополнительно автоматически инъектировать токены — подключите второй UseAuthClient() (через namespace AuthClient.Middleware) после первого.
HttpContext обогащается полезными элементами (UserId, OrganizationId, UserRoles, UserPermissions, AccessToken, CallingServiceId, CallingServiceName, CallingServicePermissions, InterServiceRequestId). Для удобства используйте HttpContextExtensions:
using AuthClient.Extensions;
string? userId = HttpContext.GetUserId();
string? orgId = HttpContext.GetOrganizationId();
bool isAuthn = HttpContext.IsAuthenticated();
bool canEdit = HttpContext.UserHasPermission("posts.edit");
В non‑web сценариях middleware не используются — работайте напрямую с DI.
Межсервисная авторизация (Service-to-Service)
Это ключевая «прозрачная» возможность библиотеки. После AddAuthClient(...):
- Ко всем
HttpClientв DI автоматически добавляютсяCircuitBreakerAuthHandlerиServiceToServiceAuthHandler. Любой исходящий HTTP‑вызов получает заголовкиX-Service-TokenиX-Request-Id. - Запросы к самому AuthServer заголовки не получают (защита от циклов).
- На принимающей стороне
ServiceToServiceAuthMiddlewareпроверяет токен и права черезIServiceToServiceAuthenticationService.ValidateAccessFromTokenAsyncс локальнымMemoryCache(TTL =LocalCacheExpiry, лимит =MaxLocalCacheSize).
IServiceToServiceAuthenticationService:
public interface IServiceToServiceAuthenticationService
{
Task<string> GetServiceTokenAsync(CancellationToken cancellationToken = default);
Task<ServiceAccessValidationResult> ValidateAccessFromTokenAsync(
string callingServiceToken,
string targetServiceId,
string requestId,
CancellationToken cancellationToken = default);
bool IsTokenExpiringSoon(string token, TimeSpan threshold);
Task<string> RefreshServiceTokenNowAsync(CancellationToken cancellationToken = default);
}
Чек‑лист включения:
- В
appsettings.jsonукажитеServiceId,ApiKey,ApiSecret,EnableServiceToServiceAuth=true. - В сервисе‑потребителе вызывайте обычные
HttpClient— заголовки добавятся сами. - На принимающей стороне в
Program.csвызовитеapp.UseAuthClient()доUseAuthorization(). - Для пакетной проверки прав (например, в API‑Gateway) используйте
IAuthenticationService.ValidateServiceAccessBatchAsync(serviceId, permissionCodes, ct).
Если требуется отключить S2S заголовки в одном сервисе — установите EnableServiceToServiceAuth = false.
Хранение токенов
Интерфейс ITokenStorage (AuthClient.TokenManagement):
public interface ITokenStorage
{
Task SaveTokensAsync(AuthTokens tokens, CancellationToken ct = default);
Task<AuthTokens?> GetTokensAsync(CancellationToken ct = default);
Task UpdateTokensAsync(AuthTokens tokens, CancellationToken ct = default);
Task ClearTokensAsync(CancellationToken ct = default);
Task<bool> HasValidTokensAsync(CancellationToken ct = default);
Task<string?> GetAccessTokenAsync(CancellationToken ct = default);
Task<string?> GetRefreshTokenAsync(CancellationToken ct = default);
}
Готовые реализации:
InMemoryTokenStorage— самый простой вариант для веб‑приложений за reverse proxy.FileTokenStorage— для CLI/desktop. ТребуетFilePathи (рекомендуется) шифрование.SystemKeyStoreTokenStorage— заглушка, бросаетNotImplementedException(issue AID‑326).
Подключение собственной реализации:
services.AddAuthClient(configuration);
services.AddCustomTokenStorage<MyRedisTokenStorage>();
При EncryptTokens=true обязательно задайте EncryptionKey (≥ 32 символа). Шифрование выполняется через CryptographyHelper.
ITokenRefreshService запускается как singleton background компонент и согласно TokenRefreshOptions сам обновляет токены до их истечения; внутри библиотеки используется ForceRefreshAsync() для немедленного refresh.
Обработка ошибок
Все методы возвращают объект, наследующий BaseResult. Стандартный паттерн:
var result = await _auth.LoginAsync(username, password, "my-service-id", cancellationToken: ct);
if (!result.Success)
{
_logger.LogWarning(
"Login failed: code={Code}, message={Message}, details={Details}",
result.ErrorCode, result.Message, result.ErrorDetails);
return Unauthorized(new { code = result.ErrorCode, message = result.Message });
}
Дополнительно библиотека определяет типизированные исключения (AuthClient.Exceptions):
AuthClientException— базовое;AuthenticationException— ошибки аутентификации;AuthorizationException— ошибки авторизации;ConfigurationException— невалидные настройки;ServerCommunicationException— сетевые/gRPC сбои;TokenStorageException— проблемы хранилища.
Они могут быть проброшены из инфраструктурного кода (например, при сбое gRPC). В прикладном коде обычно достаточно проверки result.Success.
Best Practices
- Один
ServiceIdна сервис — он используется и в S2S‑заголовках, и в runtime‑проверках. Не путайте сServiceCode. - Секреты — в Secret Manager:
ApiKey,ApiSecret,EncryptionKeyне должны попадать в git. - Для пользовательских прав —
ITokenValidationService.CheckPermissionAsync.IPermissionServiceнужен только администраторам каталога разрешений. - Для проверок по организации всегда передавайте
organizationId, иначе проверка будет глобальной по сервису. - Web API — обязательно вызывайте
app.UseAuthClient()(S2S middleware) доUseAuthorization(). - Не используйте
app.UseAuthClient()в Generic Host — middleware не для non‑web. Сервисы получайте через DI. - Refresh — не выключайте автообновление в production. Если делаете отдельный
RefreshTokenAsync, не забывайтеITokenStorage.UpdateTokensAsync. - Локальный кэш S2S — настраивайте
LocalCacheExpiry/MaxLocalCacheSizeпод нагрузку. По умолчанию 15 минут / 10 000 записей. - Retry политики — для нагруженных операций ставьте
Strategy=ExponentialBackoff,UseJitter=true. Не задирайтеMaxRetryAttemptsвыше 5. - AutoMapper в DEBUG — при сборке в Debug запускается
AutoMapperValidationService, который проверяет конфигурацию профилей при старте. Не отключайте — это ловит несовместимости proto и моделей.
Совместимость и версионирование
- Целевой framework:
net8.0. - gRPC сервер:
AIDesk.AuthServer.Contracts(версия фиксируется вcsproj). - Версия пакета формируется через Nerdbank.GitVersioning (
version.json). Семантика — SemVer:- MAJOR — breaking changes публичного API;
- MINOR — обратно‑совместимая функциональность;
- PATCH — багфиксы.
- Поддерживаются Windows, Linux, macOS (определены символы
WINDOWS,LINUX,MACOS).
История изменений ведётся в репозитории AuthServer (docs/projects/AuthClient/CHANGELOG.md). Подробные прикладные сценарии — в docs/projects/AuthClient/USAGE_EXAMPLES.md.
Лицензия и ссылки
- Лицензия: MIT.
- NuGet:
AIDeskLab.AuthClient - Репозиторий и документация: github.com/aidesklab/authclient
No packages depend on AIDeskLab.AuthClient.
.NET 8.0
- AIDesk.AuthServer.Contracts (>= 1.0.2-gc79506c63a)
- AutoMapper (>= 13.0.1)
- Google.Protobuf (>= 3.28.3)
- Grpc.Net.Client (>= 2.70.0)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 8.0.0)
- Microsoft.Extensions.Caching.Memory (>= 9.0.3)
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.3)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.3)
- Microsoft.Extensions.Http (>= 9.0.3)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.3)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 9.0.3)
- Microsoft.IdentityModel.Tokens (>= 8.14.0)
- System.IdentityModel.Tokens.Jwt (>= 8.14.0)
| Version | Downloads | Last updated |
|---|---|---|
| 1.1.7 | 1 | 05/14/2026 |
| 1.1.4 | 5 | 04/29/2026 |
| 1.1.3-g1b2b06ce20 | 3 | 04/28/2026 |
| 1.0.11-gbcaac7719d | 9 | 01/16/2026 |
| 1.0.10-g8e6a734f1e | 6 | 01/16/2026 |
| 1.0.7-g470a3ef930 | 6 | 01/16/2026 |