Гейт csharp_style_var_for_built_in_types=false:warning (ломает сборку), остаток выправлен dotnet format IDE0008 по 5 sln (только встроенные типы). Понижено 12 новых XML-доков private/internal, добавлены <summary> членам IContainerRules и ITenantContext, 3 англоязычных комментария переведены на русский.
63 lines
2.4 KiB
C#
63 lines
2.4 KiB
C#
using Deal.Api.Extensions;
|
|
using Deal.Api.Models;
|
|
using Deal.Modules.Tenants.Application.Services;
|
|
using Deal.SharedKernel.Tenants.Abstractions;
|
|
using Deal.SharedKernel.Tenants.Models;
|
|
using Microsoft.Extensions.Options;
|
|
// Имя конфигурационного типа совпадает с Microsoft.AspNetCore.Http.CookieOptions — фиксируем алиасом.
|
|
using CookieOptions = Deal.Api.Configuration.CookieOptions;
|
|
|
|
namespace Deal.Api.Middleware;
|
|
|
|
/// <summary>
|
|
/// Middleware сессии
|
|
/// </summary>
|
|
public sealed class SessionMiddleware
|
|
{
|
|
private readonly RequestDelegate _next;
|
|
private readonly IOptionsMonitor<CookieOptions> _cookieOptions;
|
|
private readonly ITenantContext _tenantContext;
|
|
|
|
public SessionMiddleware(
|
|
RequestDelegate next,
|
|
IOptionsMonitor<CookieOptions> cookieOptions,
|
|
ITenantContext tenantContext)
|
|
{
|
|
_next = next;
|
|
_cookieOptions = cookieOptions;
|
|
_tenantContext = tenantContext;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Обрабатывает запрос
|
|
/// </summary>
|
|
public async Task InvokeAsync(HttpContext context)
|
|
{
|
|
try
|
|
{
|
|
string cookieName = _cookieOptions.CurrentValue.Name;
|
|
if (context.Request.Cookies.TryGetValue(cookieName, out string? rawToken)
|
|
&& !string.IsNullOrWhiteSpace(rawToken))
|
|
{
|
|
// AuthService scoped: создаём scope на запрос через RequestServices.
|
|
await using var scope = context.RequestServices.CreateAsyncScope();
|
|
var authService = scope.ServiceProvider.GetRequiredService<AuthService>();
|
|
var user = await authService.ResolveSessionAsync(rawToken, context.RequestAborted);
|
|
if (user is not null)
|
|
{
|
|
context.SetCurrentUser(new CurrentUser(user.Id, user.Login, user.TenantId, user.Status));
|
|
// Схема тенанта именуется tenant_<id>, где id — Guid в формате "N" (см. TenantService).
|
|
_tenantContext.SetTenant(new TenantId(user.TenantId.ToString("N")));
|
|
}
|
|
}
|
|
|
|
await _next(context);
|
|
}
|
|
finally
|
|
{
|
|
// Контекст AsyncLocal не должен переживать запрос.
|
|
_tenantContext.Reset();
|
|
}
|
|
}
|
|
}
|