using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using OpenIddict.Abstractions;
using OpenIddict.Server;
using static OpenIddict.Server.OpenIddictServerEvents;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
namespace Sozsoft.Platform.Identity;
///
/// /connect/revocation çağrısı başarıyla tamamlandığında ilgili kullanıcının
/// AbpSessions tablosundaki tüm satırlarını siler.
/// OpenIddict server pipeline'ına eklenir; MVC controller override gerektirmez.
///
public class PlatformSessionRevocationHandler :
IOpenIddictServerHandler,
ITransientDependency
{
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor
.CreateBuilder()
.UseScopedHandler()
.SetOrder(int.MaxValue - 10)
.SetType(OpenIddictServerHandlerType.Custom)
.Build();
private readonly IIdentitySessionRepository sessionRepo;
private readonly ICurrentTenant currentTenant;
private readonly ILogger logger;
public PlatformSessionRevocationHandler(
IIdentitySessionRepository sessionRepo,
ICurrentTenant currentTenant,
ILogger logger)
{
this.sessionRepo = sessionRepo;
this.currentTenant = currentTenant;
this.logger = logger;
}
public async ValueTask HandleAsync(HandleRevocationRequestContext context)
{
// Hata durumunda (geçersiz token, yetkisiz istek vb.) temizlik yapma.
if (context.IsRejected) return;
var userId = context.Principal?.GetClaim(OpenIddictConstants.Claims.Subject);
if (string.IsNullOrEmpty(userId) || !Guid.TryParse(userId, out var userGuid)) return;
// Token'dan tenant ID'yi al.
var tenantIdStr = context.Principal?.GetClaim(AbpClaimTypes.TenantId);
Guid? tenantId = null;
if (!string.IsNullOrWhiteSpace(tenantIdStr) && Guid.TryParse(tenantIdStr, out var parsedTenantId))
{
tenantId = parsedTenantId;
}
try
{
// Sadece token'ın ait olduğu tenant'taki oturumları sil.
using (currentTenant.Change(tenantId))
{
var sessions = await sessionRepo.GetListAsync(userId: userGuid);
foreach (var session in sessions)
{
await sessionRepo.DeleteAsync(session);
}
if (sessions.Count > 0)
{
logger.LogInformation(
"Token revocation: {Count} IdentitySession silindi. UserId: {UserId}, TenantId: {TenantId}",
sessions.Count, userGuid, tenantId);
}
}
}
catch (Exception ex)
{
// Session temizleme hatası revocation akışını bloklamamalı.
logger.LogWarning(ex,
"Token revocation sonrası IdentitySession temizliğinde hata. UserId: {UserId}", userId);
}
}
}