using Microsoft.AspNetCore.Authorization; namespace ScadaLink.Security; /// /// Authorization requirement for site-scoped deployment operations. /// public class SiteScopeRequirement : IAuthorizationRequirement { public string TargetSiteId { get; } public SiteScopeRequirement(string targetSiteId) { TargetSiteId = targetSiteId ?? throw new ArgumentNullException(nameof(targetSiteId)); } } /// /// Checks that a user with the Deployment role is permitted to operate on the target site. /// Users with Deployment role and no SiteId claims are system-wide deployers. /// Users with SiteId claims are only permitted on those specific sites. /// public class SiteScopeAuthorizationHandler : AuthorizationHandler { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, SiteScopeRequirement requirement) { // Must have Deployment role var hasDeploymentRole = context.User.HasClaim(JwtTokenService.RoleClaimType, "Deployment"); if (!hasDeploymentRole) { return Task.CompletedTask; // Fail — no Deployment role } var siteIdClaims = context.User.FindAll(JwtTokenService.SiteIdClaimType).ToList(); if (siteIdClaims.Count == 0) { // No site scope restrictions — system-wide deployer context.Succeed(requirement); } else if (siteIdClaims.Any(c => c.Value == requirement.TargetSiteId)) { // User is permitted on this specific site context.Succeed(requirement); } // Otherwise, silently fail (not authorized for this site) return Task.CompletedTask; } }