基于策略和资源的授权机制
This commit is contained in:
1 parent
2d0e504108
commit
65925ce6ef
13 files changed
+172
-51
No files matched your search
@@ -0,0 +1,32 @@
|
||||
using HelloShop.ServiceDefaults.Permissions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization.Infrastructure;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace HelloShop.ServiceDefaults.Authorization;
|
||||
|
||||
public class CustomAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options, IPermissionDefinitionManager permissionDefinitionManager) : DefaultAuthorizationPolicyProvider(options)
|
||||
{
|
||||
public override async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
|
||||
{
|
||||
AuthorizationPolicy? policy = await base.GetPolicyAsync(policyName);
|
||||
|
||||
if (policy != null)
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
var permissionDefinition = permissionDefinitionManager.GetOrNullAsync(policyName);
|
||||
|
||||
if (permissionDefinition != null)
|
||||
{
|
||||
var policyBuilder = new AuthorizationPolicyBuilder();
|
||||
|
||||
policyBuilder.Requirements.Add(new OperationAuthorizationRequirement { Name = policyName });
|
||||
|
||||
return policyBuilder.Build();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using HelloShop.ServiceDefaults.Constants;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace HelloShop.ServiceDefaults.Authorization;
|
||||
|
||||
public interface IAuthorizationResource
|
||||
{
|
||||
string ResourceType => GetType().Name;
|
||||
|
||||
string ResourceId => GetType().GetProperty(EntityConnstants.DefaultKey)?.GetValue(this)?.ToString() ?? throw new NotImplementedException();
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public abstract class PermissionChecker(IHttpContextAccessor httpContextAccessor
|
||||
|
||||
await distributedCache.SetObjectAsync(cacheKey, new PermissionGrantCacheItem(isGranted), new DistributedCacheEntryOptions
|
||||
{
|
||||
SlidingExpiration = TimeSpan.FromMinutes(10)
|
||||
AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(1)
|
||||
});
|
||||
|
||||
if (isGranted)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization.Infrastructure;
|
||||
|
||||
namespace HelloShop.ServiceDefaults.Authorization;
|
||||
|
||||
public class PermissionRequirementHandler(IPermissionChecker permissionChecker) : AuthorizationHandler<OperationAuthorizationRequirement>
|
||||
{
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement)
|
||||
{
|
||||
if (await permissionChecker.IsGrantedAsync(context.User, requirement.Name))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
return;
|
||||
}
|
||||
|
||||
context.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
public class ResourcePermissionRequirementHandler(IPermissionChecker permissionChecker) : AuthorizationHandler<OperationAuthorizationRequirement, IAuthorizationResource>
|
||||
{
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement, IAuthorizationResource resource)
|
||||
{
|
||||
if (await permissionChecker.IsGrantedAsync(context.User, requirement.Name, resource.ResourceType, resource.ResourceId))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace HelloShop.ServiceDefaults.Authorization;
|
||||
|
||||
public class ResourceInfo : IAuthorizationResource
|
||||
{
|
||||
public required string ResourceType { get; set; }
|
||||
|
||||
public required string ResourceId { get; set; }
|
||||
|
||||
public static implicit operator string(ResourceInfo resource) => resource.ToString();
|
||||
|
||||
public static explicit operator ResourceInfo(string resourcePath)
|
||||
{
|
||||
string[] separators = resourcePath.Split(":");
|
||||
|
||||
if (separators == null || separators.Length != 2)
|
||||
{
|
||||
throw new ArgumentException("Resource path must be in the format 'type:id'", nameof(resourcePath));
|
||||
}
|
||||
|
||||
ResourceInfo resourceInfo = new() { ResourceType = separators.First(), ResourceId = separators.Last() };
|
||||
|
||||
return resourceInfo;
|
||||
}
|
||||
|
||||
|
||||
public override string ToString() => $"{ResourceType}:{ResourceId}";
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace HelloShop.ServiceDefaults.Constants;
|
||||
|
||||
public static class EntityConnstants
|
||||
{
|
||||
public const string DefaultKey = "Id";
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using HelloShop.ServiceDefaults.Authorization;
|
||||
using HelloShop.ServiceDefaults.Permissions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
@@ -72,4 +73,13 @@ public static class PermissionExtensions
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddCustomAuthorization(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IAuthorizationPolicyProvider, CustomAuthorizationPolicyProvider>();
|
||||
services.AddTransient<IAuthorizationHandler, PermissionRequirementHandler>();
|
||||
services.AddTransient<IAuthorizationHandler, ResourcePermissionRequirementHandler>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user