передача токена

This commit is contained in:
gorbenko.pavel
2026-07-24 15:33:54 +05:00
parent 40e7974244
commit a125ed2834
3 changed files with 27 additions and 6 deletions
@@ -9,8 +9,8 @@
"Postgres": "Host=localhost;Port=5435;Database=tnsu_approval_route;Username=tnsu_approval_route;Password=tnsu_approval_route" "Postgres": "Host=localhost;Port=5435;Database=tnsu_approval_route;Username=tnsu_approval_route;Password=tnsu_approval_route"
}, },
"Entra": { "Entra": {
"TenantId": "", "TenantId": "b4c2af35-bfd6-4cff-9af9-556efb53e65a",
"Audience": "" "Audience": "9232d9e2-9807-4753-808f-07250e5474b0"
}, },
"Dev": { "Dev": {
"DefaultUserEmail": "dev@tnsu.kz" "DefaultUserEmail": "dev@tnsu.kz"
@@ -13,5 +13,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
<PackageReference Include="Microsoft.Extensions.Http" /> <PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
<!-- Даёт доступ к IHttpContextAccessor из общего фреймворка ASP.NET Core (тот же тип, что в Api). -->
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -1,14 +1,23 @@
using System.Net; using System.Net;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Http;
using Tnsu.ApprovalRoute.Domain.Enums; using Tnsu.ApprovalRoute.Domain.Enums;
namespace Tnsu.ApprovalRoute.Infrastructure.TnsuPortal; namespace Tnsu.ApprovalRoute.Infrastructure.TnsuPortal;
// Клиент api.tnsu.kz (api-tnsu-portal). Сервисный токен прокидывается через TnsuPortalTokenProvider. // Клиент api.tnsu.kz (api-tnsu-portal).
public sealed class HttpTnsuPortalClient(HttpClient httpClient, TnsuPortalTokenProvider tokenProvider) : ITnsuPortalClient public sealed class HttpTnsuPortalClient(
HttpClient httpClient,
TnsuPortalTokenProvider tokenProvider,
IHttpContextAccessor httpContextAccessor) : ITnsuPortalClient
{ {
// Разные эндпоинты api-tnsu-portal отдают JSON в разном регистре (Dapper-результаты — PascalCase,
// строго типизированные модели — camelCase), поэтому сопоставляем поля без учёта регистра.
private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true };
public async Task<EmployeeDirectoryInfo?> GetEmployeeByEmailAsync(string email, CancellationToken cancellationToken) public async Task<EmployeeDirectoryInfo?> GetEmployeeByEmailAsync(string email, CancellationToken cancellationToken)
{ {
using var request = new HttpRequestMessage(HttpMethod.Get, $"/Employee/ByEmail?email={Uri.EscapeDataString(email)}"); using var request = new HttpRequestMessage(HttpMethod.Get, $"/Employee/ByEmail?email={Uri.EscapeDataString(email)}");
@@ -19,7 +28,7 @@ public sealed class HttpTnsuPortalClient(HttpClient httpClient, TnsuPortalTokenP
return null; return null;
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var employee = await response.Content.ReadFromJsonAsync<EmployeeResponse>(cancellationToken); var employee = await response.Content.ReadFromJsonAsync<EmployeeResponse>(JsonOptions, cancellationToken);
if (employee is null) if (employee is null)
return null; return null;
@@ -36,7 +45,7 @@ public sealed class HttpTnsuPortalClient(HttpClient httpClient, TnsuPortalTokenP
return []; return [];
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var project = await response.Content.ReadFromJsonAsync<ProjectResponse>(cancellationToken); var project = await response.Content.ReadFromJsonAsync<ProjectResponse>(JsonOptions, cancellationToken);
if (project is null) if (project is null)
return []; return [];
@@ -56,8 +65,18 @@ public sealed class HttpTnsuPortalClient(HttpClient httpClient, TnsuPortalTokenP
executors.Add(new ProjectExecutorInfo(role, email)); executors.Add(new ProjectExecutorInfo(role, email));
} }
// ВРЕМЕННО: для TnsuPortal ещё нет своего client-credentials приложения в Entra, поэтому прокидываем
// токен текущего пользователя дальше — его aud совпадает с ClientId api-tnsu-portal, так что подходит.
// Когда появится своё приложение — вернуть на tokenProvider.GetAccessTokenAsync(...).
private async Task AuthorizeAsync(HttpRequestMessage request, CancellationToken cancellationToken) private async Task AuthorizeAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{ {
var incoming = httpContextAccessor.HttpContext?.Request.Headers.Authorization.ToString();
if (!string.IsNullOrWhiteSpace(incoming))
{
request.Headers.TryAddWithoutValidation("Authorization", incoming);
return;
}
var token = await tokenProvider.GetAccessTokenAsync(cancellationToken); var token = await tokenProvider.GetAccessTokenAsync(cancellationToken);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
} }