权限模块

基于策略的授权是授权的核心,基于角色的授权和基于Scheme的授权只是一种语法上的便捷,最终都会生成授权策略,使用基于策略的授权时,首先要定义授权策略,而授权策略本质上就是对Claims的一系列断言。

1、先用IAuthorizationPolicyProvider根据名称得到AuthorizationPolicy,而AuthorizationPolicy对象包含IReadOnlyList Requirements列表

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的快捷方法。

IAuthorizationPolicyProvider是根据名称获取到策略对象,默认实现为DefaultAuthorizationPolicyProvider,从AuthorizationOptions _options里面获取_options.GetPolicy(policyName)

context.Services.AddAuthorization(options =>
            {
                options.AddPolicy("MyClaimTestPolicy", policy =>
                {
                    policy.RequireClaim("MyCustomClaimType", "42");
                });
            });

ABP自定义AbpAuthorizationPolicyProvider,派生DefaultAuthorizationPolicyProvider,在GetPolicyAsync方法里从IPermissionDefinitionManager得到permissiondefinition的定义,再利用AuthorizationPolicyBuilder创建AuthorizationPolicy对象

 public override async Task 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());
                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,客户化属性定义Dictionary Properties,WithProperty,WithProviders两个方法设置   

2、PermissionGroupDefinition组定义,基本同PermissionDefinition,重点方法GetPermissionsWithChildren,是递归获取所有的PermissionDefinition。

3、PermissionDefinitionContext,是组定义字典的Dictionary Groups,及一些方法AddGroup,GetGroupOrNull方法

4、IPermissionDefinitionManager,有组的定义,也有PermissionDefinition的方法,构造函数遍历Options.DefinitionProviders,遍历实现中Define方法,填充PermissionDefinitionContext,返回PermissionGroupDefinition的字典

 protected virtual Dictionary 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 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 CheckAsync(PermissionValueCheckContext context);
    }

 其一实现方法:用户UserPermissionValueProvider,用户AbpClaimTypes.UserId,角色AbpClaimTypes.Role,客户端AbpClaimTypes.ClientId,同理。

  public override async Task 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 options,
            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 Task 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进行集成

 

 

权限模块_第1张图片

权限模块_第2张图片

你可能感兴趣的:(权限模块)