首页 .Net 十、Abp vNext 基础篇丨权限

十、Abp vNext 基础篇丨权限

系列文章列表,点击展示/隐藏

系列教程一目录:知识点源码解析

系列教程二目录:Bcvp AbpVnext讲解

系列教程三目录:单个知识点讲解

系列教程四目录:分库分表(日志系统案例讲解)

本文梯子

    正文

    介绍

    本章节来把接口的权限加一下

    权限配置和使用

    官方地址:https://docs.abp.io/en/abp/latest/Authorization

    下面这种代码可能我们日常开发都写过,ASP.NET Core 提供的Authorize特性来帮我们做授权,但是BookStore_Author_Create策略,需要我们去手动声明。

    权限配置

    Abp定义了一个叫Permission System叫权限系统啥的都可以,来帮助我们轻松的搞定授权,具体怎么玩看下面代码就三部。

    权限配置

    一、定义常量

        public static >CorePermissions
        {
            public const string GroupName = "Bvcp.Core";
    
            public static >Blogs
            {
                public const string Default = GroupName + ".Blog";
                public const string Management = Default + ".Management";
                public const string Delete = Default + ".Delete";
                public const string Update = Default + ".Update";
                public const string Create = Default + ".Create";
                public const string ClearCache = Default + ".ClearCache";
            }
    
            public static >Posts
            {
                public const string Default = GroupName + ".Post";
                public const string Delete = Default + ".Delete";
                public const string Update = Default + ".Update";
                public const string Create = Default + ".Create";
            }
    
            public static >Tags
            {
                public const string Default = GroupName + ".Tag";
                public const string Delete = Default + ".Delete";
                public const string Update = Default + ".Update";
                public const string Create = Default + ".Create";
            }
    
            public static >Comments
            {
                public const string Default = GroupName + ".Comment";
                public const string Delete = Default + ".Delete";
                public const string Update = Default + ".Update";
                public const string Create = Default + ".Create";
            }
    
            public static string[] GetAll()
            {
                return ReflectionHelper.GetPublicConstantsRecursively(typeof(CorePermissions));
            }
        }
    

    二、添加权限配置

        public >CorePermissionDefinitionProvider : PermissionDefinitionProvider
        {
            public override void Define(IPermissionDefinitionContext context)
            {
                var bloggingGroup = context.AddGroup(CorePermissions.GroupName, L("Permission:Core"));
    
                var blogs = bloggingGroup.AddPermission(CorePermissions.Blogs.Default, L("Permission:Blogs"));
                blogs.AddChild(CorePermissions.Blogs.Management, L("Permission:Management"));
                blogs.AddChild(CorePermissions.Blogs.Update, L("Permission:Edit"));
                blogs.AddChild(CorePermissions.Blogs.Delete, L("Permission:Delete"));
                blogs.AddChild(CorePermissions.Blogs.Create, L("Permission:Create"));
                blogs.AddChild(CorePermissions.Blogs.ClearCache, L("Permission:ClearCache"));
    
                var posts = bloggingGroup.AddPermission(CorePermissions.Posts.Default, L("Permission:Posts"));
                posts.AddChild(CorePermissions.Posts.Update, L("Permission:Edit"));
                posts.AddChild(CorePermissions.Posts.Delete, L("Permission:Delete"));
                posts.AddChild(CorePermissions.Posts.Create, L("Permission:Create"));
    
                var tags = bloggingGroup.AddPermission(CorePermissions.Tags.Default, L("Permission:Tags"));
                tags.AddChild(CorePermissions.Tags.Update, L("Permission:Edit"));
                tags.AddChild(CorePermissions.Tags.Delete, L("Permission:Delete"));
                tags.AddChild(CorePermissions.Tags.Create, L("Permission:Create"));
    
                var comments = bloggingGroup.AddPermission(CorePermissions.Comments.Default, L("Permission:Comments"));
                comments.AddChild(CorePermissions.Comments.Update, L("Permission:Edit"));
                comments.AddChild(CorePermissions.Comments.Delete, L("Permission:Delete"));
                comments.AddChild(CorePermissions.Comments.Create, L("Permission:Create"));
            }
    
            private static LocalizableString L(string name)
            {
                return LocalizableString.Create<CoreResource>(name);
            }
        }
    

    三、使用

    Authorize(CorePermissions.Posts.Delete)]
    

    使用权限

    资源授权方案

    资源授权可能用过的人不多,代码都会在整体的修改代码一节这里先看就行,可以参考微软官方文档

    https://docs.microsoft.com/zh-cn/aspnet/core/security/authorization/resourcebased?view=aspnetcore-5.0

    有些场景下,授权需要依赖于要访问的资源,例如:每个资源通常会有一个创建者属性,我们只允许该资源的创建者才可以对其进行编辑,删除等操作,这就无法通过[Authorize]特性来指定授权了。因为授权过滤器会在我们的应用代码之前执行,无法确定所访问的资源。此时,我们需要使用基于资源的授权,下面就来演示一下具体是如何操作的。

    定义资源Requirement

    在基于资源的授权中,我们要判断的是用户是否具有针对该资源的某项操作,因此,我们先定义一个代表操作的Requirement:

        public static >CommonOperations
        {
            public static OperationAuthorizationRequirement Update = new OperationAuthorizationRequirement { Name = nameof(Update) };
            public static OperationAuthorizationRequirement Delete = new OperationAuthorizationRequirement { Name = nameof(Delete) };
        }
    

    实现资源授权Handler

    每一个 Requirement 都需要有一个对应的 Handler,来完成授权逻辑,可以直接让 Requirement 实现IAuthorizationHandler接口。

    我们是根据资源的创建者来判断用户是否具有操作权限,实现我们的授权Handler:

      public >CommentAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Comment>
        {
            private readonly IPermissionChecker _permissionChecker;
    
            public CommentAuthorizationHandler(IPermissionChecker permissionChecker)
            {
                _permissionChecker = permissionChecker;
            }
    
            protected override async Task HandleRequirementAsync(
                AuthorizationHandlerContext context,
                OperationAuthorizationRequirement requirement,
                Comment resource)
            {
                if (requirement.Name == CommonOperations.Delete.Name && await HasDeletePermission(context, resource))
                {
                    context.Succeed(requirement);
                    return;
                }
    
                if (requirement.Name == CommonOperations.Update.Name && await HasUpdatePermission(context, resource))
                {
                    context.Succeed(requirement);
                    return;
                }
            }
    
            private async Task<bool> HasDeletePermission(AuthorizationHandlerContext context, Comment resource)
            {
                // 判断创建人是否是登陆人
                if (resource.CreatorId != null && resource.CreatorId == context.User.FindUserId())
                {
                    return true;
                }
                // 判断当前用户是否满足资源操作策略
                if (await _permissionChecker.IsGrantedAsync(context.User, CorePermissions.Comments.Delete))
                {
                    return true;
                }
    
                return false;
            }
    
            private async Task<bool> HasUpdatePermission(AuthorizationHandlerContext context, Comment resource)
            {
                 // 判断创建人是否是登陆人
                if (resource.CreatorId != null && resource.CreatorId == context.User.FindUserId())
                {
                    return true;
                }
                // 判断当前用户是否满足资源操作策略
                if (await _permissionChecker.IsGrantedAsync(context.User, CorePermissions.Comments.Update))
                {
                    return true;
                }
    
                return false;
            }
        }
    

    注册Handler,这一点不要忘了

     public >CoreApplicationModule : AbpModule
        {
            public override void ConpServices(ServiceConfigurationContext context)
            {
                Conp<AbpAutoMapperOptions>(options =>
                {
                    options.AddMaps<CoreApplicationModule>();
                });
    
                Conp<AuthorizationOptions>(options =>
                {
                    options.AddPolicy("BloggingUpdatePolicy", policy => policy.Requirements.Add(CommonOperations.Update));
                    options.AddPolicy("BloggingDeletePolicy", policy => policy.Requirements.Add(CommonOperations.Delete));
                });
    
                context.Services.AddSingleton<IAuthorizationHandler, CommentAuthorizationHandler>();
                context.Services.AddSingleton<IAuthorizationHandler, PostAuthorizationHandler>();
             
    
            }
        }
    

    使用策略授权

            [Authorize]
            public async Task<CommentWithDetailsDto> UpdateAsync(Guid id, UpdateCommentDto input)
            {
    
                var comment = await _commentRepository.GetAsync(id);
                // 检测是否有权限
                await AuthorizationService.CheckAsync(comment, CommonOperations.Update);
    
                comment.SetText(input.Text);
    
                comment = await _commentRepository.UpdateAsync(comment);
    
                return ObjectMapper.Map<Comment, CommentWithDetailsDto>(comment);
            }
    

    整体的修改代码

    整体结构

     public static >CommonOperations
        {
            public static OperationAuthorizationRequirement Update = new OperationAuthorizationRequirement { Name = nameof(Update) };
            public static OperationAuthorizationRequirement Delete = new OperationAuthorizationRequirement { Name = nameof(Delete) };
        }
    
     public >CommentAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Comment>
        {
            private readonly IPermissionChecker _permissionChecker;
    
            public CommentAuthorizationHandler(IPermissionChecker permissionChecker)
            {
                _permissionChecker = permissionChecker;
            }
    
            protected override async Task HandleRequirementAsync(
                AuthorizationHandlerContext context,
                OperationAuthorizationRequirement requirement,
                Comment resource)
            {
                if (requirement.Name == CommonOperations.Delete.Name && await HasDeletePermission(context, resource))
                {
                    context.Succeed(requirement);
                    return;
                }
    
                if (requirement.Name == CommonOperations.Update.Name && await HasUpdatePermission(context, resource))
                {
                    context.Succeed(requirement);
                    return;
                }
            }
    
            private async Task<bool> HasDeletePermission(AuthorizationHandlerContext context, Comment resource)
            {
                if (resource.CreatorId != null && resource.CreatorId == context.User.FindUserId())
                {
                    return true;
                }
    
                if (await _permissionChecker.IsGrantedAsync(context.User, CorePermissions.Comments.Delete))
                {
                    return true;
                }
    
                return false;
            }
    
            private async Task<bool> HasUpdatePermission(AuthorizationHandlerContext context, Comment resource)
            {
                if (resource.CreatorId != null && resource.CreatorId == context.User.FindUserId())
                {
                    return true;
                }
    
                if (await _permissionChecker.IsGrantedAsync(context.User, CorePermissions.Comments.Update))
                {
                    return true;
                }
    
                return false;
            }
        }
    
      public >PostAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Post>
        {
            private readonly IPermissionChecker _permissionChecker;
    
            public PostAuthorizationHandler(IPermissionChecker permissionChecker)
            {
                _permissionChecker = permissionChecker;
            }
    
            protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement,
                Post resource)
            {
    
                if (requirement.Name == CommonOperations.Delete.Name && await HasDeletePermission(context, resource))
                {
                    context.Succeed(requirement);
                    return;
                }
    
                if (requirement.Name == CommonOperations.Update.Name && await HasUpdatePermission(context, resource))
                {
                    context.Succeed(requirement);
                    return;
                }
    
            }
    
            private async Task<bool> HasDeletePermission(AuthorizationHandlerContext context, Post resource)
            {
                if (resource.CreatorId != null && resource.CreatorId == context.User.FindUserId())
                {
                    return true;
                }
    
                if (await _permissionChecker.IsGrantedAsync(context.User, CorePermissions.Posts.Delete))
                {
                    return true;
                }
    
                return false;
            }
    
            private async Task<bool> HasUpdatePermission(AuthorizationHandlerContext context, Post resource)
            {
                if (resource.CreatorId != null && resource.CreatorId == context.User.FindUserId())
                {
                    return true;
                }
    
                if (await _permissionChecker.IsGrantedAsync(context.User, CorePermissions.Posts.Update))
                {
                    return true;
                }
    
                return false;
            }
        }
    

    CoreApplicationModule.cs

     public >CoreApplicationModule : AbpModule
        {
            public override void ConpServices(ServiceConfigurationContext context)
            {
                Conp<AbpAutoMapperOptions>(options =>
                {
                    options.AddMaps<CoreApplicationModule>();
                });
    
                // 注册
                Conp<AuthorizationOptions>(options =>
                {
                    options.AddPolicy("BloggingUpdatePolicy", policy => policy.Requirements.Add(CommonOperations.Update));
                    options.AddPolicy("BloggingDeletePolicy", policy => policy.Requirements.Add(CommonOperations.Delete));
                });
    
                context.Services.AddSingleton<IAuthorizationHandler, CommentAuthorizationHandler>();
                context.Services.AddSingleton<IAuthorizationHandler, PostAuthorizationHandler>();
             
    
            }
        }
    

    CommentAppService.cs

            [Authorize]
            public async Task<CommentWithDetailsDto> UpdateAsync(Guid id, UpdateCommentDto input)
            {
    
                var comment = await _commentRepository.GetAsync(id);
    
                await AuthorizationService.CheckAsync(comment, CommonOperations.Update);
    
                comment.SetText(input.Text);
    
                comment = await _commentRepository.UpdateAsync(comment);
    
                return ObjectMapper.Map<Comment, CommentWithDetailsDto>(comment);
            }
    
            [Authorize]
            public async Task DeleteAsync(Guid id)
            {
                var comment = await _commentRepository.GetAsync(id);
    
                await AuthorizationService.CheckAsync(comment, CommonOperations.Delete);
    
                var replies = await _commentRepository.GetRepliesOfComment(id);
    
                foreach (var reply in replies)
                {
                    await _commentRepository.DeleteAsync(reply.Id);
                }
            }
    

    PostAppService.cs

     [Authorize(CorePermissions.Posts.Delete)]
            public async Task DeleteAsync(Guid id)
            {
                // 查找文章
                var post = await _postRepository.GetAsync(id);
                // 判断是否有资源操作权
                await AuthorizationService.CheckAsync(post, CommonOperations.Delete);
                // 根据文章获取Tags
                var tags = await GetTagsOfPost(id);
                // 减少Tag引用数量
                await _tagRepository.DecreaseUsageCountOfTagsAsync(tags.Select(t => t.Id).ToList());
                // 删除评论
                await _commentRepository.DeleteOfPost(id);
                // 删除文章
                await _postRepository.DeleteAsync(id);
                await PublishPostChangedEventAsync(post.BlogId);
            }
    
            [Authorize(CorePermissions.Posts.Update)]
            public async Task<PostWithDetailsDto> UpdateAsync(Guid id, UpdatePostDto input)
            {
                var post = await _postRepository.GetAsync(id);
    
                input.Url = await RenameUrlIfItAlreadyExistAsync(input.BlogId, input.Url, post);
    
                await AuthorizationService.CheckAsync(post, CommonOperations.Update);
    
                post.SetTitle(input.Title);
                post.SetUrl(input.Url);
                post.Content = input.Content;
                post.Description = input.Description;
                post.CoverImage = input.CoverImage;
    
                post = await _postRepository.UpdateAsync(post);
    
                var tagList = SplitTags(input.Tags);
                await SaveTags(tagList, post);
                await PublishPostChangedEventAsync(post.BlogId);
                return ObjectMapper.Map<Post, PostWithDetailsDto>(post);
            }
    
    特别声明:本站部分内容收集于互联网是出于更直观传递信息的目的。该内容版权归原作者所有,并不代表本站赞同其观点和对其真实性负责。如该内容涉及任何第三方合法权利,请及时与824310991@qq.com联系,我们会及时反馈并处理完毕。