权限模块和Feature模块

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

1、先用IAuthorizationPolicyProvider根据名称得到AuthorizationPolicy,而AuthorizationPolicy对象包含IReadOnlyList<IAuthorizationRequirement> 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<TRequirement>来实现,ABP有如下定义:

依赖于_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的快捷方法。

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<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);
            }
        }
    }

 

一、模块的配置

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进行集成

 

 

 

Feature模块

首先是继承FeatureDefinitionProvider,将Feature组定义,FeatureGroupDefiniftion增加FeatureDefinition,

   public class TestFeatureDefinitionProvider : FeatureDefinitionProvider
    {
        public override void Define(IFeatureDefinitionContext context)
        {
            var group = context.AddGroup("Test Group");
            group.AddFeature("BooleanTestFeature1");
            group.AddFeature("BooleanTestFeature2");
            group.AddFeature("IntegerTestFeature1", defaultValue: "1");
        }
    }

数据库存储的是FeatureValue,FeatureDefinition的标识Name,ProviderName(Default(D)、Edition、Tenant),ProviderKey,根据需要获取是Value

IFeatureStore负责获取Value责任 

IFeatureValueProvider: Name,Task<string> GetOrNullAsync([NotNull] FeatureDefinition feature);获取特性的方式不同,默认直接从定义中获取,版本是从认证获取FindEditionId,租户获取tenantid,作为providerkey,用于给featurestore去得到值

 

FeatureChecker是检查方法,它FeatureManage首先根据Name获取得FeatureDefinition,检查允许哪些AllowedProviders,顺序是TenantFeatureValueProvider,EditionFeatureValueProvider,DefaultValueFeatureValueProvider

再由这些获取值 ,获取得到就返回Value(string),若为空,则是false,否则转移成bool

  public interface IFeatureChecker
    {
        Task<string> GetOrNullAsync([NotNull] string name);
        Task<bool> IsEnabledAsync(string name);
    }

拦截器上,当类或方法应用标识RequiresFeatureAttribute特性,应用拦截器,将方法的上下文当Context,

MethodInvocationFeatureCheckerService服务方法是拦截器,当执行方法,首先获取方法上RequiresFeature字符串,再获取类的RequiresFeature字符串,组合在一起

每个都要检查,默认是至少一个满足,则可通过,也可以设置全部满足才可通过

/// <summary>
    /// This attribute can be used on a class/method to declare that given class/method is available
    /// only if required feature(s) are enabled.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class RequiresFeatureAttribute : Attribute
    {
        /// <summary>
        /// A list of features to be checked if they are enabled.
        /// </summary>
        public string[] Features { get; }

        /// <summary>
        /// If this property is set to true, all of the <see cref="Features"/> must be enabled.
        /// If it's false, at least one of the <see cref="Features"/> must be enabled.
        /// Default: false.
        /// </summary>
        public bool RequiresAll { get; set; }

        /// <summary>
        /// Creates a new instance of <see cref="RequiresFeatureAttribute"/> class.
        /// </summary>
        /// <param name="features">A list of features to be checked if they are enabled</param>
        public RequiresFeatureAttribute(params string[] features)
        {
            Features = features ?? Array.Empty<string>();
        }
    }

IFeatureManagementProvider:根据提示FeatureDefinition,providerKey去获取和获取,首先是租户,然后是版本,才是默认

 

posted on 2019-07-13 11:42  dollymi  阅读(1039)  评论(0编辑  收藏  举报

导航