using System; using System.Linq; using System.Threading.Tasks; using Microsoft.Data.SqlClient; using Microsoft.AspNetCore.Http; using Volo.Abp; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; using Volo.Abp.Uow; namespace Sozsoft.Platform.Identity; public class PlatformSessionValidationMiddleware : IMiddleware, ITransientDependency { private readonly IIdentitySessionRepository sessionRepository; private readonly ICurrentTenant currentTenant; private readonly IUnitOfWorkManager unitOfWorkManager; public PlatformSessionValidationMiddleware( IIdentitySessionRepository sessionRepository, ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager) { this.sessionRepository = sessionRepository; this.currentTenant = currentTenant; this.unitOfWorkManager = unitOfWorkManager; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) { if (context.Request.Path.StartsWithSegments("/api/setup")) { await next(context); return; } if (context.User.Identity?.IsAuthenticated != true) { await next(context); return; } var userIdValue = context.User.FindFirst(AbpClaimTypes.UserId)?.Value; var sessionId = context.User.FindFirst(PlatformClaimTypes.SessionId.Key)?.Value; if (!Guid.TryParse(userIdValue, out var userId) || sessionId.IsNullOrWhiteSpace()) { await next(context); return; } var tenantId = ParseTenantId(context.User.FindFirst(AbpClaimTypes.TenantId)?.Value); using (currentTenant.Change(tenantId)) { try { using var uow = unitOfWorkManager.Begin(requiresNew: true, isTransactional: false); var sessions = await sessionRepository.GetListAsync(userId: userId); var isCurrentSession = sessions.Any(session => session.SessionId == sessionId); await uow.CompleteAsync(); if (!isCurrentSession) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; return; } } catch (Exception ex) when (IsDatabaseUnavailableException(ex)) { context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable; return; } } await next(context); } private static Guid? ParseTenantId(string value) { return !string.IsNullOrWhiteSpace(value) && Guid.TryParse(value, out var id) ? id : null; } private static bool IsDatabaseUnavailableException(Exception exception) { return exception is SqlException || exception is TimeoutException || exception is TaskCanceledException || exception is InvalidOperationException && exception.InnerException != null && IsDatabaseUnavailableException(exception.InnerException); } }