docs: add xml comments and update ignore rules
This commit is contained in:
@@ -1,34 +1,40 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using TakeoutSaaS.Module.Authorization.Policies;
|
||||
|
||||
namespace TakeoutSaaS.Module.Authorization.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// 权限校验特性
|
||||
/// 权限校验特性。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public sealed class PermissionAuthorizeAttribute : AuthorizeAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化权限校验特性并构建对应策略。
|
||||
/// </summary>
|
||||
/// <param name="permissions">所需的权限标识集合。</param>
|
||||
public PermissionAuthorizeAttribute(params string[] permissions)
|
||||
{
|
||||
// 1. 校验权限参数不为空
|
||||
ArgumentNullException.ThrowIfNull(permissions);
|
||||
|
||||
// 2. 规范化权限标识
|
||||
var normalized = permissions
|
||||
.Where(p => !string.IsNullOrWhiteSpace(p))
|
||||
.Select(p => p.Trim())
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
// 3. 确保至少提供一个有效权限
|
||||
if (normalized.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("至少需要一个权限标识", nameof(permissions));
|
||||
}
|
||||
|
||||
// 4. 绑定权限集合并生成策略名称
|
||||
Permissions = normalized;
|
||||
Policy = PermissionAuthorizationPolicyProvider.BuildPolicyName(normalized);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所需权限集合
|
||||
/// 所需权限集合。
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<string> Permissions { get; }
|
||||
}
|
||||
|
||||
@@ -1,38 +1,45 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace TakeoutSaaS.Module.Authorization.Policies;
|
||||
|
||||
/// <summary>
|
||||
/// 权限校验处理器
|
||||
/// 权限校验处理器。
|
||||
/// </summary>
|
||||
public sealed class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户声明中权限的声明类型键。
|
||||
/// </summary>
|
||||
public const string PermissionClaimType = "permission";
|
||||
|
||||
/// <summary>
|
||||
/// 校验当前用户是否具备要求的权限集合。
|
||||
/// </summary>
|
||||
/// <param name="context">授权上下文。</param>
|
||||
/// <param name="requirement">权限需求描述。</param>
|
||||
/// <returns>异步完成任务。</returns>
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
|
||||
{
|
||||
// 1. 校验用户已通过认证
|
||||
if (context.User?.Identity?.IsAuthenticated != true)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// 2. 收集用户已授予的权限标识
|
||||
var userPermissions = context.User
|
||||
.FindAll(PermissionClaimType)
|
||||
.Select(claim => claim.Value)
|
||||
.Where(value => !string.IsNullOrWhiteSpace(value))
|
||||
.Select(value => value.Trim())
|
||||
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// 3. 无权限直接结束
|
||||
if (userPermissions.Count == 0)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// 4. 任一权限匹配即视为授权通过
|
||||
if (requirement.Permissions.Any(userPermissions.Contains))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
|
||||
// 5. 结束处理
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,62 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace TakeoutSaaS.Module.Authorization.Policies;
|
||||
|
||||
/// <summary>
|
||||
/// 权限策略提供者(按需动态构建策略)
|
||||
/// 权限策略提供者(按需动态构建策略)。
|
||||
/// </summary>
|
||||
public sealed class PermissionAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options) : DefaultAuthorizationPolicyProvider(options)
|
||||
{
|
||||
/// <summary>
|
||||
/// 权限策略名称前缀。
|
||||
/// </summary>
|
||||
public const string PolicyPrefix = "PERMISSION:";
|
||||
private readonly AuthorizationOptions _options = options.Value;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或构建指定名称的权限策略。
|
||||
/// </summary>
|
||||
/// <param name="policyName">策略名称。</param>
|
||||
/// <returns>匹配的授权策略。</returns>
|
||||
public override Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
|
||||
{
|
||||
if (policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
// 1. 非权限策略走基类逻辑
|
||||
if (!policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var existingPolicy = _options.GetPolicy(policyName);
|
||||
if (existingPolicy != null)
|
||||
{
|
||||
return Task.FromResult<AuthorizationPolicy?>(existingPolicy);
|
||||
}
|
||||
|
||||
var permissions = ParsePermissions(policyName);
|
||||
if (permissions.Length == 0)
|
||||
{
|
||||
return Task.FromResult<AuthorizationPolicy?>(null);
|
||||
}
|
||||
|
||||
var policy = new AuthorizationPolicyBuilder()
|
||||
.AddRequirements(new PermissionRequirement(permissions))
|
||||
.Build();
|
||||
|
||||
_options.AddPolicy(policyName, policy);
|
||||
return Task.FromResult<AuthorizationPolicy?>(policy);
|
||||
return base.GetPolicyAsync(policyName);
|
||||
}
|
||||
|
||||
return base.GetPolicyAsync(policyName);
|
||||
// 2. 复用已存在的策略
|
||||
var existingPolicy = _options.GetPolicy(policyName);
|
||||
if (existingPolicy != null)
|
||||
{
|
||||
return Task.FromResult<AuthorizationPolicy?>(existingPolicy);
|
||||
}
|
||||
// 3. 解析策略携带的权限列表
|
||||
var permissions = ParsePermissions(policyName);
|
||||
if (permissions.Length == 0)
|
||||
{
|
||||
return Task.FromResult<AuthorizationPolicy?>(null);
|
||||
}
|
||||
// 4. 动态构建策略并缓存
|
||||
var policy = new AuthorizationPolicyBuilder()
|
||||
.AddRequirements(new PermissionRequirement(permissions))
|
||||
.Build();
|
||||
_options.AddPolicy(policyName, policy);
|
||||
// 5. 返回构建好的策略
|
||||
return Task.FromResult<AuthorizationPolicy?>(policy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据权限集合构建策略名称
|
||||
/// 根据权限集合构建策略名称。
|
||||
/// </summary>
|
||||
/// <param name="permissions">权限标识集合。</param>
|
||||
/// <returns>策略名称。</returns>
|
||||
public static string BuildPolicyName(IEnumerable<string> permissions)
|
||||
=> $"{PolicyPrefix}{string.Join('|', NormalizePermissions(permissions))}";
|
||||
|
||||
private static string[] ParsePermissions(string policyName)
|
||||
{
|
||||
// 1. 拆分策略名称得到原始权限列表
|
||||
var raw = policyName[PolicyPrefix.Length..];
|
||||
// 2. 规范化并过滤权限
|
||||
return NormalizePermissions(raw.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
|
||||
}
|
||||
|
||||
private static string[] NormalizePermissions(IEnumerable<string> permissions)
|
||||
=> [.. permissions
|
||||
.Where(p => !string.IsNullOrWhiteSpace(p))
|
||||
|
||||
Reference in New Issue
Block a user