using Fitness_core_BE.Interfaces.Services; using Fitness_core_BE.Models.IOs; using Microsoft.AspNetCore.Mvc.Filters; namespace Fitness_core_BE.Helpers { // Gates an action/controller behind one nav-section permission key. Must run AFTER // CustomMiddlewareAttribute (which populates HttpContext.Items["UserId"]) — guaranteed by // Order below, since CustomMiddlewareAttribute has no IOrderedFilter and runs at the // ASP.NET Core default Order (0), regardless of attribute declaration order on the method. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public class RequiresPermissionAttribute : Attribute, IAsyncActionFilter, IOrderedFilter { private readonly string _navKey; public int Order => 10; public RequiresPermissionAttribute(string navKey) { _navKey = navKey; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var permissionService = context.HttpContext.RequestServices.GetService(typeof(IPermissionService)) as IPermissionService; var ctx = await permissionService!.GetPermissionContextAsync(context.HttpContext); if (!ctx.IsOwner && !ctx.AllowedNavKeys.Contains(_navKey)) { context.HttpContext.Response.StatusCode = 403; await context.HttpContext.Response.WriteAsJsonAsync(new ApiResponse { StatusCode = 403, Message = "You don't have permission to access this feature.", Data = null }); return; } await next(); } } }