подписка
Tests / frontend-test (pull_request) Successful in 47s
Tests / backend-test (pull_request) Successful in 2m36s

This commit is contained in:
gorbenko.pavel
2026-08-19 13:30:09 +05:00
parent cf44ae3e2e
commit a1e6c5c8b4
12 changed files with 443 additions and 21 deletions
@@ -0,0 +1,39 @@
using System.Net.Http.Headers;
namespace Tnsu.ApprovalRoute.Infrastructure.TnsuPortal;
/// <summary>
/// Авторизация запросов к api.tnsu.kz. Вынесена из HttpTnsuPortalClient, потому что
/// к порталу ходит не только справочник сотрудников (см.
/// HttpSharePointWebhookSubscriber), а правило выбора токена должно быть одно.
///
/// Токен берётся в двух режимах, и порядок принципиален:
/// 1) Токен вызывающего пользователя (см. TnsuPortalCallerToken) — из текущего
/// HTTP-запроса либо переданный аргументом в фоновую задачу. Портал тогда
/// видит исходного пользователя, а не сервисное приложение.
/// 2) Его нет вовсе — client_credentials самого сервиса (см.
/// TnsuPortalTokenProvider).
///
/// ВАЖНО про второй путь: TnsuPortal:ClientSecret/Scope в конфигурации пусты
/// (см. appsettings.json), поэтому он сейчас нерабочий — это именно фолбэк, а не
/// штатный режим. Вызывающая сторона обязана это учитывать: см.
/// HttpSharePointWebhookSubscriber, где сбой подписки намеренно не рушит
/// провижининг списка.
/// </summary>
public sealed class TnsuPortalAuthorizer(
TnsuPortalCallerToken callerToken,
TnsuPortalTokenProvider tokenProvider)
{
public async Task AuthorizeAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var caller = callerToken.Current;
if (!string.IsNullOrWhiteSpace(caller))
{
request.Headers.TryAddWithoutValidation("Authorization", caller);
return;
}
var token = await tokenProvider.GetAccessTokenAsync(cancellationToken);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
}