基于策略的授权是授权的核心,基于角色的授权和基于Scheme的授权只是一种语法上的便捷,最终都会生成授权策略,使用基于策略的授权时,首先要定义授权策略,而授权策略本质上就是对Claims的一系列断言。
1、先用IAuthorizationPolicyProvider根据名称得到AuthorizationPolicy,而AuthorizationPolicy对象包含IReadOnlyList
2、 每一个 Requirement 都需要有一个对应的 Handler(IAuthorizationHandler)来完成授权逻辑.
3、IAuthorizationService的工作原理:首先根据策略名字,由IAuthorizationPolicyProvider得到AuthorizationPolicy,然后由require对应的Handler进行验证
每一个Requirement都代表一个授权条件;比如DenyAnonymousAuthorizationRequirement 表示禁止匿名用户访问的授权策略;ClaimsAuthorizationRequirement 用于表示判断Cliams中是否包含预期的Claims的授权策略。
ABP,定义一个代表操作的Requirement:
public class PermissionRequirement : IAuthorizationRequirement
{
public string PermissionName { get; }
public PermissionRequirement([NotNull]string permissionName)
{
Check.NotNull(permissionName, nameof(permissionName));
PermissionName = permissionName;
}
}
每一个 Requirement 都需要有一个对应的 Handler来完成授权逻辑,可以直接让 Requirement 实现IAuthorizationHandler
接口,也可以单独定义授权Handler
我们在实现IAuthorizationHandler
接口时,通常是继承自AuthorizationHandler
来实现,ABP有如下定义:
依赖于_permissionChecker进行验证
public class PermissionRequirementHandler : AuthorizationHandler{ private readonly IPermissionChecker _permissionChecker; public PermissionRequirementHandler(IPermissionChecker permissionChecker) { _permissionChecker = permissionChecker; } protected override async Task HandleRequirementAsync( AuthorizationHandlerContext context, PermissionRequirement requirement) { if (await _permissionChecker.IsGrantedAsync(context.User, requirement.PermissionName)) { context.Succeed(requirement); } } }
授权策略具体表现为一个AuthorizationPolicy
对象,要判断的是用户是否具有针对该资源的某项操作,
AuthorizationPolicyBuilder,它提供了一系列创建AuthorizationPolicy
的快捷方法。
context.Services.AddAuthorization(options => { options.AddPolicy("MyClaimTestPolicy", policy => { policy.RequireClaim("MyCustomClaimType", "42"); }); });
ABP自定义AbpAuthorizationPolicyProvider,派生DefaultAuthorizationPolicyProvider,在GetPolicyAsync方法里从IPermissionDefinitionManager得到permissiondefinition的定义,再利用AuthorizationPolicyBuilder创建AuthorizationPolicy
对象
public override async TaskGetPolicyAsync(string policyName) { var policy = await base.GetPolicyAsync(policyName); if (policy != null) { return policy; } var permission = _permissionDefinitionManager.GetOrNull(policyName); if (permission != null) { //TODO: Optimize & Cache! var policyBuilder = new AuthorizationPolicyBuilder(Array.Empty ()); policyBuilder.Requirements.Add(new PermissionRequirement(policyName)); return policyBuilder.Build(); } return null; }
权限是主要是通过调用IAuthorizationService
来完成的,而授权策略的本质是提供 Requirement ,我们完全可以使用它们两个来完成各种灵活的授权方式,而不用局限于策略;在默认的AuthorizationHandlerProvider中,会从DI系统中获取到我们注册的所有Handler,最终调用其HandleAsync
方法。;
public class DefaultAuthorizationService : IAuthorizationService
{
private readonly AuthorizationOptions _options;
private readonly IAuthorizationHandlerContextFactory _contextFactory;
private readonly IAuthorizationHandlerProvider _handlers;
private readonly IAuthorizationEvaluator _evaluator;
private readonly IAuthorizationPolicyProvider _policyProvider; public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) { var policy = await _policyProvider.GetPolicyAsync(policyName); return await this.AuthorizeAsync(user, resource, policy); } public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements) { var authContext = _contextFactory.CreateContext(requirements, user, resource); var handlers = await _handlers.GetHandlersAsync(authContext); foreach (var handler in handlers) { await handler.HandleAsync(authContext); if (!_options.InvokeHandlersAfterFailure && authContext.HasFailed) { break; } } return _evaluator.Evaluate(authContext); } }
public abstract class AuthorizationHandler: IAuthorizationHandler where TRequirement : IAuthorizationRequirement { public virtual async Task HandleAsync(AuthorizationHandlerContext context) { foreach (var req in context.Requirements.OfType ()) { await HandleRequirementAsync(context, req); } } protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement);
public class PermissionRequirementHandler : AuthorizationHandler{ private readonly IPermissionChecker _permissionChecker; public PermissionRequirementHandler(IPermissionChecker permissionChecker) { _permissionChecker = permissionChecker; } protected override async Task HandleRequirementAsync( AuthorizationHandlerContext context, PermissionRequirement requirement) { if (await _permissionChecker.IsGrantedAsync(context.User, requirement.PermissionName)) { context.Succeed(requirement); } } }
一、模块的配置
1、增加权限拦截器,只要类型和方法有AuthorizeAttribute都增加AuthorizationInterceptor
public static void RegisterIfNeeded(IOnServiceRegistredContext context) { if (ShouldIntercept(context.ImplementationType)) { context.Interceptors.TryAdd(); } } private static bool ShouldIntercept(Type type) { return type.IsDefined(typeof(AuthorizeAttribute), true) || AnyMethodHasAuthorizeAttribute(type); }
2、PermissionOptions权限的两个集合,权限的定义IPermissionDefinitionProvider,以及权限的提供者IPermissionValueProvider
注册PermissionRequirementHandler到DI系统里面
public override void PreConfigureServices(ServiceConfigurationContext context) { context.Services.OnRegistred(AuthorizationInterceptorRegistrar.RegisterIfNeeded); AutoAddDefinitionProviders(context.Services); } public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAuthorization(); context.Services.AddSingleton(); Configure (options => { options.ValueProviders.Add (); options.ValueProviders.Add (); options.ValueProviders.Add (); }); }
1)PermissionDefinition的定义有,名称,父定义Parent ,租户端(Tenant,Host,Both),允许providers(指的valueProvider) ,显示名字,子权限Children列表List
2、PermissionGroupDefinition组定义,基本同PermissionDefinition,重点方法GetPermissionsWithChildren,是递归获取所有的PermissionDefinition。
3、PermissionDefinitionContext,是组定义字典的Dictionary
4、IPermissionDefinitionManager,有组的定义,也有PermissionDefinition的方法,构造函数遍历Options.DefinitionProviders,遍历实现中Define方法,填充PermissionDefinitionContext,返回PermissionGroupDefinition的字典
protected virtual DictionaryCreatePermissionGroupDefinitions() { var context = new PermissionDefinitionContext(); using (var scope = _serviceProvider.CreateScope()) { var providers = Options .DefinitionProviders .Select(p => scope.ServiceProvider.GetRequiredService(p) as IPermissionDefinitionProvider) .ToList(); foreach (var provider in providers) { provider.Define(context); } } return context.Groups; }
2 权限的提供者IPermissionValueProvider(三个分别是用户、角色和客户端),其主要方法 Task
其中:PermissionValueCheckContext的上下文要引入PermissionDefinition要鉴权的权限定义以及ClaimsPrincipal(用户的信息)。PermissionValueCheckContext的构建见PermissionChecker类;它是调用IPermissionValueProvider来获取是否存在权限;var context = new PermissionValueCheckContext(permission, claimsPrincipal);
IPermissionValueProvider的抽象方法PermissionValueProvider,注入IPermissionStore
public abstract class PermissionValueProvider : IPermissionValueProvider, ISingletonDependency //TODO: to transient? { public abstract string Name { get; } protected IPermissionStore PermissionStore { get; } protected PermissionValueProvider(IPermissionStore permissionStore) { PermissionStore = permissionStore; } public abstract TaskCheckAsync(PermissionValueCheckContext context); }
其一实现方法:用户UserPermissionValueProvider,用户AbpClaimTypes.UserId,角色AbpClaimTypes.Role,客户端AbpClaimTypes.ClientId,同理。
public override async TaskCheckAsync(PermissionValueCheckContext context) { var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; if (userId == null) { return PermissionGrantResult.Undefined; } return await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, userId) ? PermissionGrantResult.Granted : PermissionGrantResult.Undefined; }
二、IPermissionChecker是检查既定的认证信息是否有权限,见构造函数
public PermissionChecker( IOptionsoptions, IServiceProvider serviceProvider, ICurrentPrincipalAccessor principalAccessor, IPermissionDefinitionManager permissionDefinitionManager, ICurrentTenant currentTenant) { PrincipalAccessor = principalAccessor; PermissionDefinitionManager = permissionDefinitionManager; CurrentTenant = currentTenant; Options = options.Value; _lazyProviders = new Lazy >( () => Options .ValueProviders .Select(c => serviceProvider.GetRequiredService(c) as IPermissionValueProvider) .ToList(), true ); }
这是权限判断的方法,遍历IPermissionValueProvider在Options里面ValueProviders字典
public virtual async TaskIsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name) { Check.NotNull(name, nameof(name)); var permission = PermissionDefinitionManager.Get(name); var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ?? CurrentTenant.GetMultiTenancySide(); if (!permission.MultiTenancySide.HasFlag(multiTenancySide)) { return false; } var isGranted = false; var context = new PermissionValueCheckContext(permission, claimsPrincipal); foreach (var provider in ValueProviders) { if (context.Permission.Providers.Any() && !context.Permission.Providers.Contains(provider.Name)) { continue; } var result = await provider.CheckAsync(context); if (result == PermissionGrantResult.Granted) { isGranted = true; } else if (result == PermissionGrantResult.Prohibited) { return false; } } return isGranted; }
4、IMethodInvocationAuthorizationService,用于拦截器
protected async Task CheckAsync(IAuthorizeData authorizationAttribute) { if (authorizationAttribute.Policy == null) { //TODO: Can we find a better, unified, way of checking if current request has been authenticated if (!_currentUser.IsAuthenticated && !_currentClient.IsAuthenticated) { throw new AbpAuthorizationException("Authorization failed! User has not logged in."); } } else { await _authorizationService.CheckAsync(authorizationAttribute.Policy); } //TODO: What about roles and other props? }
Asp.net Core的认证和授权,ABP进行集成