// Copyright (c) HelloShop Corporation. All rights reserved. // See the license file in the project root for more information. using HelloShop.ServiceDefaults.Constants; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Distributed; using System.Security.Claims; namespace HelloShop.ServiceDefaults.Authorization; public abstract class PermissionChecker(IHttpContextAccessor httpContextAccessor, IDistributedCache distributedCache,TimeProvider timeProvider) : IPermissionChecker { protected HttpContext HttpContext { get; init; } = httpContextAccessor.HttpContext ?? throw new InvalidOperationException(); public async Task IsGrantedAsync(string permissionName, string? resourceType = null, string? resourceId = null) => await IsGrantedAsync(HttpContext.User, permissionName, resourceType, resourceId); public async Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string permissionName, string? resourceType = null, string? resourceId = null) { var roleIds = claimsPrincipal.FindAll(CustomClaimTypes.RoleIdentifier).Select(c => Convert.ToInt32(c.Value)).ToArray(); foreach (var roleId in roleIds) { var cacheKey = PermissionGrantCacheItem.CreateCacheKey(roleId, permissionName, resourceType, resourceId); if (distributedCache.TryGetValue(cacheKey, out PermissionGrantCacheItem? cacheItem) && cacheItem != null) { if (cacheItem.IsGranted) { return true; } continue; } bool isGranted = await IsGrantedAsync(roleId, permissionName, resourceType, resourceId); await distributedCache.SetObjectAsync(cacheKey, new PermissionGrantCacheItem(isGranted), new DistributedCacheEntryOptions { AbsoluteExpiration = timeProvider.GetUtcNow() }); if (isGranted) { return true; } } return false; } public abstract Task IsGrantedAsync(int roleId, string permissionName, string? resourceType = null, string? resourceId = null); }