using System.Net.Http.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.Options; namespace Tnsu.ApprovalRoute.Infrastructure.TnsuPortal; public sealed class TnsuPortalTokenProvider(HttpClient httpClient, IOptions options) { private string? _cachedToken; private DateTimeOffset _expiresAt = DateTimeOffset.MinValue; public async Task GetAccessTokenAsync(CancellationToken cancellationToken) { if (_cachedToken is not null && DateTimeOffset.UtcNow < _expiresAt) return _cachedToken; var opts = options.Value; var response = await httpClient.PostAsync( $"https://login.microsoftonline.com/{opts.TenantId}/oauth2/v2.0/token", new FormUrlEncodedContent(new Dictionary { ["grant_type"] = "client_credentials", ["client_id"] = opts.ClientId, ["client_secret"] = opts.ClientSecret, ["scope"] = opts.Scope }), cancellationToken); response.EnsureSuccessStatusCode(); var payload = await response.Content.ReadFromJsonAsync(cancellationToken) ?? throw new InvalidOperationException("Не удалось получить токен для api.tnsu.kz."); _cachedToken = payload.AccessToken; _expiresAt = DateTimeOffset.UtcNow.AddSeconds(payload.ExpiresIn - 60); return _cachedToken; } private sealed record TokenResponse( [property: JsonPropertyName("access_token")] string AccessToken, [property: JsonPropertyName("expires_in")] int ExpiresIn); }