From da2eb5d8981e9d7f8e0772a41ef492b93c2f9b34 Mon Sep 17 00:00:00 2001 From: Nguyen Quang Chien Date: Sat, 29 Jul 2023 20:27:46 +0700 Subject: [PATCH] feat: users tracking --- src/Api/Controllers/DashboardController.cs | 18 ++++++++++++++++++ src/Api/Services/BackgroundWorkers.cs | 15 ++++++++++++++- .../Authorization/RequiresRoleAttribute.cs | 17 +++++++++++------ 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 src/Api/Controllers/DashboardController.cs diff --git a/src/Api/Controllers/DashboardController.cs b/src/Api/Controllers/DashboardController.cs new file mode 100644 index 00000000..35ced3e8 --- /dev/null +++ b/src/Api/Controllers/DashboardController.cs @@ -0,0 +1,18 @@ +using Application.Common.Models; +using Application.Identity; +using Infrastructure.Identity.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Api.Controllers; + +public class DashboardController : ApiControllerBase +{ + [RequiresRole(IdentityData.Roles.Admin)] + [HttpGet("online-users")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task> GetOnlineUsers() + { + return Ok(Result.Succeed(RequiresRoleAttribute.OnlineUsers.Count)); + } +} \ No newline at end of file diff --git a/src/Api/Services/BackgroundWorkers.cs b/src/Api/Services/BackgroundWorkers.cs index baf37b11..0068d066 100644 --- a/src/Api/Services/BackgroundWorkers.cs +++ b/src/Api/Services/BackgroundWorkers.cs @@ -1,5 +1,6 @@ using Application.Common.Interfaces; using Domain.Statuses; +using Infrastructure.Identity.Authorization; using Microsoft.EntityFrameworkCore; using NodaTime; @@ -22,7 +23,8 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { DisposeExpiredEntries(TimeSpan.FromSeconds(10), stoppingToken), DisposeExpiredPermissions(TimeSpan.FromSeconds(10), stoppingToken), - HandleOverdueRequest(TimeSpan.FromMinutes(2),stoppingToken), + HandleOverdueRequest(TimeSpan.FromMinutes(2), stoppingToken), + HandleOnlineUsers(TimeSpan.FromSeconds(10), stoppingToken), }; await Task.WhenAll(workers.ToArray()); @@ -74,4 +76,15 @@ private async Task HandleOverdueRequest(TimeSpan delay, CancellationToken stoppi await context.SaveChangesAsync(stoppingToken); await Task.Delay(delay, stoppingToken); } + + private async Task HandleOnlineUsers(TimeSpan delay, CancellationToken stoppingToken) + { + var onlineUsers = RequiresRoleAttribute.OnlineUsers; + foreach (var id in onlineUsers.Keys + .Where(id => DateTime.Now - onlineUsers[id] < delay)) + { + RequiresRoleAttribute.OnlineUsers.Remove(id); + } + await Task.Delay(delay, stoppingToken); + } } \ No newline at end of file diff --git a/src/Infrastructure/Identity/Authorization/RequiresRoleAttribute.cs b/src/Infrastructure/Identity/Authorization/RequiresRoleAttribute.cs index 469e1e98..a1c63d21 100644 --- a/src/Infrastructure/Identity/Authorization/RequiresRoleAttribute.cs +++ b/src/Infrastructure/Identity/Authorization/RequiresRoleAttribute.cs @@ -1,5 +1,5 @@ +using System.Collections.Immutable; using System.IdentityModel.Tokens.Jwt; -using Application.Identity; using Infrastructure.Persistence; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -11,6 +11,7 @@ namespace Infrastructure.Identity.Authorization; public class RequiresRoleAttribute : Attribute, IAuthorizationFilter { private readonly string[] _claimValues; + public static Dictionary OnlineUsers { get; } = new(); public RequiresRoleAttribute(params string[] claimValues) { @@ -25,12 +26,16 @@ public void OnAuthorization(AuthorizationFilterContext context) var user = dbContext.Users.FirstOrDefault(x => x.Email!.Equals(email)); - foreach (var claimValue in _claimValues) + if (user is null) { - if (user!.Role.Equals(claimValue)) - { - return; - } + context.Result = new ForbidResult(); + return; + } + + if (_claimValues.Any(claimValue => user!.Role.Equals(claimValue))) + { + OnlineUsers[user.Id] = DateTime.Now; + return; } context.Result = new ForbidResult();