Sla (#11)
Tests / backend-test (push) Successful in 1m50s
Tests / frontend-test (push) Successful in 49s

Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/11
This commit was merged in pull request #11.
This commit is contained in:
2026-08-13 04:44:08 +00:00
parent 7f2aabbf29
commit d076f4e98d
103 changed files with 2606 additions and 1265 deletions
@@ -0,0 +1,42 @@
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<TnsuPortalOptions> options)
{
private string? _cachedToken;
private DateTimeOffset _expiresAt = DateTimeOffset.MinValue;
public async Task<string> 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<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = opts.ClientId,
["client_secret"] = opts.ClientSecret,
["scope"] = opts.Scope
}),
cancellationToken);
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadFromJsonAsync<TokenResponse>(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);
}