Added permission checks to all controllers. Added role permission loading. Added frontend permission checks. Implemented user logout in admin panel.

This commit was merged in pull request #4.
This commit is contained in:
2026-01-16 13:07:19 +01:00
parent bee381702b
commit a28b8aca7a
24 changed files with 401 additions and 62 deletions

View File

@@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Authorization;
using Moonlight.Shared;
namespace Moonlight.Frontend.Implementations;
public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionRequirement requirement)
{
var permissionClaim = context.User.FindFirst(x =>
x.Type.Equals(Permissions.ClaimType, StringComparison.OrdinalIgnoreCase) &&
x.Value.Equals(requirement.Identifier, StringComparison.OrdinalIgnoreCase)
);
if (permissionClaim == null)
{
context.Fail(new AuthorizationFailureReason(
this,
$"User does not have the requested permission '{requirement.Identifier}'"
));
return Task.CompletedTask;
}
context.Succeed(requirement);
return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Moonlight.Shared;
namespace Moonlight.Frontend.Implementations;
public class PermissionPolicyProvider : IAuthorizationPolicyProvider
{
private readonly DefaultAuthorizationPolicyProvider FallbackProvider;
public PermissionPolicyProvider(IOptions<AuthorizationOptions> options)
{
FallbackProvider = new DefaultAuthorizationPolicyProvider(options);
}
public async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
if (!policyName.StartsWith(Permissions.Prefix, StringComparison.OrdinalIgnoreCase))
return await FallbackProvider.GetPolicyAsync(policyName);
var policy = new AuthorizationPolicyBuilder();
policy.AddRequirements(new PermissionRequirement(policyName));
return policy.Build();
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
=> FallbackProvider.GetDefaultPolicyAsync();
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
=> FallbackProvider.GetFallbackPolicyAsync();
}
public class PermissionRequirement : IAuthorizationRequirement
{
public string Identifier { get; }
public PermissionRequirement(string identifier)
{
Identifier = identifier;
}
}

View File

@@ -10,11 +10,23 @@ public sealed class PermissionProvider : IPermissionProvider
public Task<PermissionCategory[]> GetPermissionsAsync()
{
return Task.FromResult<PermissionCategory[]>([
new PermissionCategory("User Management", typeof(UsersRoundIcon), [
new Permission(Permissions.Admin.Users.Create, "Create", "Create new users"),
new Permission(Permissions.Admin.Users.View, "View", "View all users"),
new Permission(Permissions.Admin.Users.Edit, "Edit", "Edit user details"),
new Permission(Permissions.Admin.Users.Delete, "Delete", "Delete user accounts"),
new PermissionCategory("Users", typeof(UserRoundIcon), [
new Permission(Permissions.Users.Create, "Create", "Create new users"),
new Permission(Permissions.Users.View, "View", "View all users"),
new Permission(Permissions.Users.Edit, "Edit", "Edit user details"),
new Permission(Permissions.Users.Delete, "Delete", "Delete user accounts"),
new Permission(Permissions.Users.Logout, "Logout", "Logout user accounts"),
]),
new PermissionCategory("Roles", typeof(UsersRoundIcon), [
new Permission(Permissions.Roles.Create, "Create", "Create new roles"),
new Permission(Permissions.Roles.View, "View", "View all roles"),
new Permission(Permissions.Roles.Edit, "Edit", "Edit role details"),
new Permission(Permissions.Roles.Delete, "Delete", "Delete role accounts"),
new Permission(Permissions.Roles.Members, "Members", "Manage role members"),
]),
new PermissionCategory("System", typeof(CogIcon), [
new Permission(Permissions.System.Info, "Info", "View system info"),
new Permission(Permissions.System.Diagnose, "Diagnose", "Run diagnostics"),
]),
]);
}

View File

@@ -1,6 +1,7 @@
using LucideBlazor;
using Moonlight.Frontend.Interfaces;
using Moonlight.Frontend.Models;
using Moonlight.Shared;
namespace Moonlight.Frontend.Implementations;
@@ -24,7 +25,8 @@ public sealed class SidebarProvider : ISidebarProvider
Path = "/admin",
IsExactPath = true,
Group = "Admin",
Order = 0
Order = 0,
Policy = Permissions.System.Info
},
new()
{
@@ -33,7 +35,8 @@ public sealed class SidebarProvider : ISidebarProvider
Path = "/admin/users",
IsExactPath = false,
Group = "Admin",
Order = 10
Order = 10,
Policy = Permissions.Users.View
},
new()
{
@@ -42,7 +45,8 @@ public sealed class SidebarProvider : ISidebarProvider
Path = "/admin/system",
IsExactPath = false,
Group = "Admin",
Order = 20
Order = 20,
Policy = Permissions.System.Info
}
]);
}