KoogleApp/src/Koogle.Infrastructure/Security/ClubRoleRequirement.cs

92 lines
2.7 KiB
C#

using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Koogle.Infrastructure.Security;
public static class ClubRoleHelper
{
public static Task CheckClubRole(
AuthorizationHandlerContext context,
ClubRoleRequirement requirement,
Guid clubId)
{
static int Rank(string role) => role switch
{
"Admin" => 3,
"Editor" => 2,
"Viewer" => 1,
_ => 0
};
var requiredRank = Rank(requirement.RequiredRole);
// Read all club_role claims
var claims = context.User.FindAll("club_role");
foreach (var c in claims)
{
// Format: "{clubId}:{roleName}"
var parts = c.Value.Split(':', 2);
if (parts.Length != 2) continue;
if (Guid.TryParse(parts[0], out var claimClubId) && claimClubId == clubId)
{
var userRole = parts[1];
if (Rank(userRole) >= requiredRank)
{
context.Succeed(requirement);
break;
}
}
}
return Task.CompletedTask;
}
}
public sealed class ClubRoleRequirement : IAuthorizationRequirement
{
public ClubRoleRequirement(string requiredRole) => RequiredRole = requiredRole;
public string RequiredRole { get; }
}
/// <summary>
/// Handles ClubRoleRequirement when no resource is passed (e.g., [Authorize(Policy = "ClubViewer")]).
/// Uses current_club_id claim to determine the club context.
/// </summary>
public sealed class ClubRoleHandler : AuthorizationHandler<ClubRoleRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
ClubRoleRequirement requirement)
{
// Get current club from claims
var currentClubClaim = context.User.FindFirst("current_club_id");
if (currentClubClaim == null || !Guid.TryParse(currentClubClaim.Value, out var clubId))
{
return Task.CompletedTask; // No club context, fail
}
return ClubRoleHelper.CheckClubRole(context, requirement, clubId);
}
}
/// <summary>
/// Handles ClubRoleRequirement when a specific clubId resource is passed.
/// </summary>
public sealed class ClubRoleResourceHandler : AuthorizationHandler<ClubRoleRequirement, Guid>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
ClubRoleRequirement requirement,
Guid clubId)
{
return ClubRoleHelper.CheckClubRole(context, requirement, clubId);
}
}