天天看点

Abp授权之交并集问题处理

在Abp(aspnet boilerplate)中,授权AbpAuthorizeAttribute可以标记在类和方法中,其默认的规则为并集处理,即满足 (类中的权限  && 方法中的权限)

但有时候,我们往往需要的是方法的权限覆盖类的权限.

打个比方:

在默认样本工程中的UserAppService.cs文件中.开头的定义如下

[AbpAuthorize(PermissionNames.Pages_Users)]
    public class UserAppService : AsyncCrudAppService<User, UserDto, long, PagedUserResultRequestDto, CreateUserDto, UserDto>, IUserAppService
    {
        ...//此处省略代码

        public async Task<bool> ChangePassword(ChangePasswordDto input)
        {
        }

        ...//此处省略代码
    }
           

该接口是用来维护所有用户的接口,但是其修改密码的接口,是需要面向全部用户的.

这里我们就需要 在方法的上面添加注释,来覆盖类中原有的注释.因为不可能所有的用户都有[Users]的权限

接下来我们就需要改写授权规则.

在Application层新建一个cs文件,命名随意,我这命名MyAuthorizationHelper,继承AuthorizationHelper类,完整代码如下;

public class MyAuthorizationHelper : AuthorizationHelper
    {
        private IAuthorizationConfiguration _authConfiguration;

        public MyAuthorizationHelper(IFeatureChecker featureChecker, IAuthorizationConfiguration authConfiguration) : base(featureChecker, authConfiguration)
        {
            _authConfiguration = authConfiguration;
        }

        [UnitOfWork]
        public override async Task AuthorizeAsync(IEnumerable<IAbpAuthorizeAttribute> authorizeAttributes)
        {
            if (!_authConfiguration.IsEnabled)
            {
                return;
            }

            if (!AbpSession.UserId.HasValue)
            {
                throw new AbpAuthorizationException(
                    LocalizationManager.GetString(AbpConsts.LocalizationSourceName, "CurrentUserDidNotLoginToTheApplication")
                );
            }

            if (authorizeAttributes!=null && authorizeAttributes.Any())
            {
                var authorizeAttribute = authorizeAttributes.First();
                await PermissionChecker.AuthorizeAsync(authorizeAttribute.RequireAllPermissions, authorizeAttribute.Permissions);
            }

            //foreach (var authorizeAttribute in authorizeAttributes)
            //{
            //    await PermissionChecker.AuthorizeAsync(authorizeAttribute.RequireAllPermissions, authorizeAttribute.Permissions);
            //}
        }

        public override void Authorize(IEnumerable<IAbpAuthorizeAttribute> authorizeAttributes)
        {
            if (!_authConfiguration.IsEnabled)
            {
                return;
            }

            if (!AbpSession.UserId.HasValue)
            {
                throw new AbpAuthorizationException(
                    LocalizationManager.GetString(AbpConsts.LocalizationSourceName, "CurrentUserDidNotLoginToTheApplication")
                );
            }
            if (authorizeAttributes != null && authorizeAttributes.Any())
            {
                var authorizeAttribute = authorizeAttributes.First();
                PermissionChecker.Authorize(authorizeAttribute.RequireAllPermissions, authorizeAttribute.Permissions);
            }

            //foreach (var authorizeAttribute in authorizeAttributes)
            //{
            //    PermissionChecker.Authorize(authorizeAttribute.RequireAllPermissions, authorizeAttribute.Permissions);
            //}
        }
    }
           

其中注释掉的部分为原Abp的设计,这里改成了只取最底层属性,即 方法中有Attribute,就拿方法中的去校验,没有则取类中的attribute

这样我们再回到UserAppService中,给ChangePassword方法增加一个属性就可以愉快的贡献出接口啦.

[AbpAuthorize(PermissionNames.Pages_Users)]
    public class UserAppService : AsyncCrudAppService<User, UserDto, long, PagedUserResultRequestDto, CreateUserDto, UserDto>, IUserAppService
    {
        ...//此处省略代码
        [AbpAuthorize()]//<-----这里
        public async Task<bool> ChangePassword(ChangePasswordDto input)
        {
        }

        ...//此处省略代码
    }
           

修改完毕后,别忘了去Module中去替换一下

在PreInitialize方法中添加下面的代码替换授权类.

Configuration.ReplaceService<IAuthorizationHelper, MyAuthorizationHelper>();
           

PS:标题的命名实在不知道该怎么命名,如各位有好的关键字,欢迎留言.谢谢各位看官了