一、模块的配置
1、增加权限拦截器,只要类型和方法有AuthorizeAttribute都增加AuthorizationInterceptor
public static void RegisterIfNeeded(IOnServiceRegistredContext context)
{
if (ShouldIntercept(context.ImplementationType))
{
context.Interceptors.TryAdd<AuthorizationInterceptor>();
}
}
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<IAuthorizationHandler, PermissionRequirementHandler>(); Configure<PermissionOptions>(options => { options.ValueProviders.Add<UserPermissionValueProvider>(); options.ValueProviders.Add<RolePermissionValueProvider>(); options.ValueProviders.Add<ClientPermissionValueProvider>(); }); }
1)PermissionDefinition的定义有,名称,父定义Parent ,租户端(Tenant,Host,Both),允许providers(指的valueProvider) ,显示名字,子权限Children列表List<PermissionDefinition>,客户化属性定义Dictionary<string, object> Properties,WithProperty,WithProviders两个方法设置
2、PermissionGroupDefinition组定义,基本同PermissionDefinition,重点方法GetPermissionsWithChildren,是递归获取所有的PermissionDefinition。
3、PermissionDefinitionContext,是组定义字典的Dictionary<string, PermissionGroupDefinition> Groups,及一些方法AddGroup,GetGroupOrNull方法
4、IPermissionDefinitionManager,有组的定义,也有PermissionDefinition的方法,构造函数遍历Options.DefinitionProviders,遍历实现中Define方法,填充PermissionDefinitionContext,返回PermissionGroupDefinition的字典
protected virtual Dictionary<string, PermissionGroupDefinition> CreatePermissionGroupDefinitions()
{
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<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context);返回是结果是Undefined,Granted,Prohibited的其中的一个
其中: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 Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context); }
其一实现方法:用户UserPermissionValueProvider,用户AbpClaimTypes.UserId,角色AbpClaimTypes.Role,客户端AbpClaimTypes.ClientId,同理。
public override async Task<PermissionGrantResult> CheckAsync(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(
IOptions<PermissionOptions> options,
IServiceProvider serviceProvider,
ICurrentPrincipalAccessor principalAccessor,
IPermissionDefinitionManager permissionDefinitionManager,
ICurrentTenant currentTenant)
{
PrincipalAccessor = principalAccessor;
PermissionDefinitionManager = permissionDefinitionManager;
CurrentTenant = currentTenant;
Options = options.Value;
_lazyProviders = new Lazy<List<IPermissionValueProvider>>(
() => Options
.ValueProviders
.Select(c => serviceProvider.GetRequiredService(c) as IPermissionValueProvider)
.ToList(),
true
);
}
这是权限判断的方法,遍历IPermissionValueProvider在Options里面ValueProviders字典
public virtual async Task<bool> IsGrantedAsync(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进行集成
基于策略的授权是授权的核心,基于角色的授权和基于Scheme的授权,只是一种语法上的便捷,最终都会生成授权策略,使用基于策略的授权时,首先要定义授权策略,而授权策略本质上就是对Claims的一系列断言。
每一个Requirement都代表一个授权条件;比如DenyAnonymousAuthorizationRequirement 表示禁止匿名用户访问的授权策略;ClaimsAuthorizationRequirement 用于表示判断Cliams中是否包含预期的Claims的授权策略。
因此,我们先定义一个代表操作的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<TRequirement>
来实现,它有如下定义:
依赖于_permissionChecker进行验证
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement> { 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
的快捷方法。
ABP自定义AbpAuthorizationPolicyProvider,派生DefaultAuthorizationPolicyProvider,在GetPolicyAsync方法里从IPermissionDefinitionManager得到permissiondefinition的定义,再利用AuthorizationPolicyBuilder创建AuthorizationPolicy
对象
public override async Task<AuthorizationPolicy> GetPolicyAsync(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<string>()); 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<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) { var policy = await _policyProvider.GetPolicyAsync(policyName); return await this.AuthorizeAsync(user, resource, policy); } public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> 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<TRequirement> : IAuthorizationHandler where TRequirement : IAuthorizationRequirement { public virtual async Task HandleAsync(AuthorizationHandlerContext context) { foreach (var req in context.Requirements.OfType<TRequirement>()) { await HandleRequirementAsync(context, req); } } protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement);
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement> { 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); } } }