设计权限定义和权限提供者
This commit is contained in:
1 parent
6742812bf2
commit
5a170f3024
14 files changed
+418
-12
No files matched your search
@@ -0,0 +1,65 @@
|
||||
using HelloShop.ServiceDefaults.Permissions;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Reflection;
|
||||
|
||||
namespace HelloShop.ServiceDefaults.Extensions;
|
||||
|
||||
public static class PermissionExtensions
|
||||
{
|
||||
public static IServiceCollection AddPermissionDefinitions(this IServiceCollection services, Assembly? assembly = null)
|
||||
{
|
||||
assembly ??= Assembly.GetCallingAssembly();
|
||||
|
||||
var permissionDefinitionProviders = assembly.ExportedTypes.Where(t => t.IsAssignableTo(typeof(IPermissionDefinitionProvider)));
|
||||
|
||||
permissionDefinitionProviders.ToList().ForEach(t => services.AddSingleton(typeof(IPermissionDefinitionProvider), t));
|
||||
|
||||
services.AddSingleton<IPermissionDefinitionManager, PermissionDefinitionManager>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IEndpointRouteBuilder MapPermissionDefinitions(this IEndpointRouteBuilder endpoints, params string[] tags)
|
||||
{
|
||||
var routeGroup = endpoints.MapGroup(string.Empty);
|
||||
|
||||
routeGroup.MapGet("PermissionDefinitions", async (IPermissionDefinitionManager permissionDefinitionManager) =>
|
||||
{
|
||||
List<PermissionGroupDefinitionResponse> result = [];
|
||||
|
||||
var permissionGroups = await permissionDefinitionManager.GetGroupsAsync();
|
||||
|
||||
foreach (var permissionGroup in permissionGroups)
|
||||
{
|
||||
PermissionGroupDefinitionResponse permissionGroupDefinition = new()
|
||||
{
|
||||
Name = permissionGroup.Name,
|
||||
DisplayName = permissionGroup.DisplayName,
|
||||
Permissions = []
|
||||
};
|
||||
|
||||
foreach (PermissionDefinition? permission in permissionGroup.GetPermissionsWithChildren())
|
||||
{
|
||||
PermissionDefinitionResponse permissionDefinition = new()
|
||||
{
|
||||
Name = permission.Name,
|
||||
DisplayName = permission.DisplayName,
|
||||
ParentName = permission.Parent?.Name
|
||||
};
|
||||
|
||||
permissionGroupDefinition.Permissions.Add(permissionDefinition);
|
||||
}
|
||||
|
||||
result.Add(permissionGroupDefinition);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}).WithTags(tags);
|
||||
|
||||
return routeGroup;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace HelloShop.ServiceDefaults.Permissions;
|
||||
|
||||
public class PermissionDefinitionResponse
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
public string? ParentName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace HelloShop.ServiceDefaults.Permissions;
|
||||
|
||||
public class PermissionGroupDefinitionResponse
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
public required List<PermissionDefinitionResponse> Permissions { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace HelloShop.ServiceDefaults.Permissions;
|
||||
|
||||
public interface IPermissionDefinitionManager
|
||||
{
|
||||
Task<PermissionDefinition> GetAsync(string name);
|
||||
|
||||
Task<PermissionDefinition?> GetOrNullAsync(string name);
|
||||
|
||||
Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync();
|
||||
|
||||
Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace HelloShop.ServiceDefaults.Permissions;
|
||||
|
||||
public interface IPermissionDefinitionProvider
|
||||
{
|
||||
void Define(PermissionDefinitionContext context);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace HelloShop.ServiceDefaults.Permissions;
|
||||
|
||||
public class PermissionDefinition
|
||||
{
|
||||
public string Name { get; } = default!;
|
||||
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
public PermissionDefinition? Parent { get; private set; }
|
||||
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
private readonly List<PermissionDefinition> _children = [];
|
||||
|
||||
public IReadOnlyList<PermissionDefinition> Children => [.. _children];
|
||||
|
||||
protected internal PermissionDefinition(string name, string? displayName = null, bool isEnabled = true)
|
||||
{
|
||||
Name = name;
|
||||
DisplayName = displayName;
|
||||
IsEnabled = isEnabled;
|
||||
}
|
||||
|
||||
public virtual PermissionDefinition AddChild(string name, string? displayName = null, bool isEnabled = true)
|
||||
{
|
||||
var child = new PermissionDefinition(name, displayName, isEnabled) { Parent = this };
|
||||
_children.Add(child);
|
||||
return child;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
namespace HelloShop.ServiceDefaults.Permissions;
|
||||
|
||||
public class PermissionDefinitionContext
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
internal Dictionary<string, PermissionGroupDefinition> Groups { get; }
|
||||
|
||||
internal PermissionDefinitionContext(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
Groups = [];
|
||||
}
|
||||
|
||||
public virtual PermissionGroupDefinition AddGroup(string name, string? displayName = null)
|
||||
{
|
||||
if (Groups.ContainsKey(name))
|
||||
{
|
||||
throw new InvalidOperationException($"There is already an existing permission group with name: {name}");
|
||||
}
|
||||
|
||||
return Groups[name] = new PermissionGroupDefinition(name, displayName);
|
||||
}
|
||||
|
||||
public virtual PermissionGroupDefinition GetGroup(string name)
|
||||
{
|
||||
PermissionGroupDefinition? group = GetGroupOrNull(name);
|
||||
|
||||
return group is null ? throw new InvalidOperationException($"Could not find a permission definition group with the given name: {name}") : group;
|
||||
}
|
||||
|
||||
public virtual PermissionGroupDefinition? GetGroupOrNull(string name)
|
||||
{
|
||||
if (!Groups.TryGetValue(name, out PermissionGroupDefinition? value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public virtual void RemoveGroup(string name)
|
||||
{
|
||||
if (!Groups.ContainsKey(name))
|
||||
{
|
||||
throw new InvalidOperationException($"Not found permission group with name: {name}");
|
||||
}
|
||||
|
||||
Groups.Remove(name);
|
||||
}
|
||||
|
||||
public virtual PermissionDefinition? GetPermissionOrNull(string name)
|
||||
{
|
||||
foreach (var groupDefinition in Groups.Values)
|
||||
{
|
||||
var permissionDefinition = groupDefinition.GetPermissionOrNull(name);
|
||||
|
||||
if (permissionDefinition != null)
|
||||
{
|
||||
return permissionDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace HelloShop.ServiceDefaults.Permissions;
|
||||
|
||||
public class PermissionDefinitionManager : IPermissionDefinitionManager
|
||||
{
|
||||
private readonly Lazy<Dictionary<string, PermissionGroupDefinition>> _lazyPermissionGroupDefinitions;
|
||||
|
||||
protected IDictionary<string, PermissionGroupDefinition> PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value;
|
||||
|
||||
private readonly Lazy<Dictionary<string, PermissionDefinition>> _lazyPermissionDefinitions;
|
||||
|
||||
protected IDictionary<string, PermissionDefinition> PermissionDefinitions => _lazyPermissionDefinitions.Value;
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public PermissionDefinitionManager(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_lazyPermissionGroupDefinitions = new Lazy<Dictionary<string, PermissionGroupDefinition>>(CreatePermissionGroupDefinitions, isThreadSafe: true);
|
||||
_lazyPermissionDefinitions = new Lazy<Dictionary<string, PermissionDefinition>>(CreatePermissionDefinitions, isThreadSafe: true);
|
||||
}
|
||||
|
||||
protected virtual Dictionary<string, PermissionGroupDefinition> CreatePermissionGroupDefinitions()
|
||||
{
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
|
||||
var context = new PermissionDefinitionContext(scope.ServiceProvider);
|
||||
|
||||
var providers = _serviceProvider.GetServices<IPermissionDefinitionProvider>();
|
||||
|
||||
foreach (IPermissionDefinitionProvider provider in providers)
|
||||
{
|
||||
provider.Define(context);
|
||||
}
|
||||
|
||||
return context.Groups;
|
||||
}
|
||||
|
||||
protected virtual Dictionary<string, PermissionDefinition> CreatePermissionDefinitions()
|
||||
{
|
||||
var permissions = new Dictionary<string, PermissionDefinition>();
|
||||
|
||||
foreach (var groupDefinition in PermissionGroupDefinitions.Values)
|
||||
{
|
||||
foreach (var permission in groupDefinition.Permissions)
|
||||
{
|
||||
AddPermissionToDictionaryRecursively(permissions, permission);
|
||||
}
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
protected virtual void AddPermissionToDictionaryRecursively(Dictionary<string, PermissionDefinition> permissions, PermissionDefinition permission)
|
||||
{
|
||||
if (permissions.ContainsKey(permission.Name))
|
||||
{
|
||||
throw new InvalidOperationException($"Duplicate permission name {permission.Name}");
|
||||
}
|
||||
|
||||
permissions[permission.Name] = permission;
|
||||
|
||||
foreach (var child in permission.Children)
|
||||
{
|
||||
AddPermissionToDictionaryRecursively(permissions, child);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<PermissionDefinition> GetAsync(string name)
|
||||
{
|
||||
var permission = await GetOrNullAsync(name);
|
||||
|
||||
return permission ?? throw new InvalidOperationException($"Undefined permission {name}");
|
||||
}
|
||||
|
||||
public Task<PermissionDefinition?> GetOrNullAsync(string name)
|
||||
{
|
||||
return Task.FromResult(PermissionDefinitions.TryGetValue(name, out var obj) ? obj : default);
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
|
||||
{
|
||||
IReadOnlyList<PermissionGroupDefinition> permissionGroups = [.. PermissionGroupDefinitions.Values];
|
||||
|
||||
return Task.FromResult(permissionGroups);
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync()
|
||||
{
|
||||
IReadOnlyList<PermissionDefinition> permissions = [.. PermissionDefinitions.Values];
|
||||
|
||||
return Task.FromResult(permissions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
namespace HelloShop.ServiceDefaults.Permissions;
|
||||
|
||||
public class PermissionGroupDefinition
|
||||
{
|
||||
public string Name { get; } = default!;
|
||||
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
private readonly List<PermissionDefinition> _permissions = [];
|
||||
|
||||
public IReadOnlyList<PermissionDefinition> Permissions => [.. _permissions];
|
||||
|
||||
protected internal PermissionGroupDefinition(string name, string? displayName = null)
|
||||
{
|
||||
Name = name;
|
||||
DisplayName = displayName;
|
||||
}
|
||||
|
||||
public virtual PermissionDefinition AddPermission(string name, string? displayName = null, bool isEnabled = true)
|
||||
{
|
||||
var permission = new PermissionDefinition(name, displayName, isEnabled);
|
||||
_permissions.Add(permission);
|
||||
return permission;
|
||||
}
|
||||
|
||||
public virtual List<PermissionDefinition> GetPermissionsWithChildren()
|
||||
{
|
||||
var permissions = new List<PermissionDefinition>();
|
||||
|
||||
foreach (var permission in _permissions)
|
||||
{
|
||||
AddPermissionToListRecursively(permissions, permission);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
private static void AddPermissionToListRecursively(List<PermissionDefinition> permissions, PermissionDefinition permission)
|
||||
{
|
||||
permissions.Add(permission);
|
||||
|
||||
foreach (var child in permission.Children)
|
||||
{
|
||||
AddPermissionToListRecursively(permissions, child);
|
||||
}
|
||||
}
|
||||
|
||||
public PermissionDefinition? GetPermissionOrNull(string name) => GetPermissionOrNullRecursively(Permissions, name);
|
||||
|
||||
private static PermissionDefinition? GetPermissionOrNullRecursively(IReadOnlyList<PermissionDefinition> permissions, string name)
|
||||
{
|
||||
foreach (var permission in permissions)
|
||||
{
|
||||
if (permission.Name == name)
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
|
||||
var childPermission = GetPermissionOrNullRecursively(permission.Children, name);
|
||||
if (childPermission != null)
|
||||
{
|
||||
return childPermission;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user