58 lines
2.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|