Files
jobtrackingapp/JobTrackerApi/Services/SessionRevocation.cs
T

58 lines
2.5 KiB
C#

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using JobTrackerApi.Data;
using Microsoft.EntityFrameworkCore;
namespace JobTrackerApi.Services;
public static class SessionRevocation
{
public static async Task RevokeCurrentAsync(JobTrackerContext db, string userId, string sessionId, CancellationToken cancellationToken)
{
var session = await db.UserSessions.IgnoreQueryFilters()
.FirstOrDefaultAsync(x => x.Id == sessionId && x.UserId == userId && x.RevokedAtUtc == null, cancellationToken);
if (session is null) return;
session.RevokedAtUtc = DateTimeOffset.UtcNow;
await db.SaveChangesAsync(cancellationToken);
}
public static async Task RevokeAllAsync(JobTrackerContext db, string userId, string? trustedDeviceHashToKeep, CancellationToken cancellationToken)
{
var sessions = await db.UserSessions.IgnoreQueryFilters()
.Where(x => x.UserId == userId && x.RevokedAtUtc == null)
.ToListAsync(cancellationToken);
var devices = await db.TrustedDevices.IgnoreQueryFilters()
.Where(x => x.UserId == userId && (trustedDeviceHashToKeep == null || x.TokenHash != trustedDeviceHashToKeep))
.ToListAsync(cancellationToken);
var now = DateTimeOffset.UtcNow;
foreach (var session in sessions) session.RevokedAtUtc = now;
db.TrustedDevices.RemoveRange(devices);
if (sessions.Count > 0 || devices.Count > 0)
await db.SaveChangesAsync(cancellationToken);
}
public static bool TryReadIdentity(ClaimsPrincipal principal, string? cookieToken, out string userId, out string sessionId)
{
userId = principal.FindFirstValue(ClaimTypes.NameIdentifier) ?? principal.FindFirstValue("sub") ?? "";
sessionId = principal.FindFirstValue("sid") ?? "";
if (userId.Length > 0 && sessionId.Length > 0) return true;
if (string.IsNullOrWhiteSpace(cookieToken) || cookieToken.Length > 16_384) return false;
var handler = new JwtSecurityTokenHandler { MapInboundClaims = false };
if (!handler.CanReadToken(cookieToken)) return false;
try
{
var token = handler.ReadJwtToken(cookieToken);
userId = token.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier || x.Type == "sub")?.Value ?? "";
sessionId = token.Claims.FirstOrDefault(x => x.Type == "sid")?.Value ?? "";
return userId.Length > 0 && sessionId.Length > 0;
}
catch
{
return false;
}
}
}