• 十、Abp vNext 基础篇丨权限


    介绍

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

    权限配置和使用

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

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

    权限配置

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

    权限配置

    一、定义常量

        public static class CorePermissions
        {
            public const string GroupName = "Bvcp.Core";
    
            public static class 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 class 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 class 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 class 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 class 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 class 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 class 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 class CoreApplicationModule : AbpModule
        {
            public override void ConfigureServices(ServiceConfigurationContext context)
            {
                Configure<AbpAutoMapperOptions>(options =>
                {
                    options.AddMaps<CoreApplicationModule>();
                });
    
                Configure<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 class CommonOperations
        {
            public static OperationAuthorizationRequirement Update = new OperationAuthorizationRequirement { Name = nameof(Update) };
            public static OperationAuthorizationRequirement Delete = new OperationAuthorizationRequirement { Name = nameof(Delete) };
        }
    
     public class 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 class 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 class CoreApplicationModule : AbpModule
        {
            public override void ConfigureServices(ServiceConfigurationContext context)
            {
                Configure<AbpAutoMapperOptions>(options =>
                {
                    options.AddMaps<CoreApplicationModule>();
                });
    
                // 注册
                Configure<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);
            }
    
  • 相关阅读:
    TCP 连接状态
    可视化垃圾回收算法
    flume-ng+Kafka+Storm+HDFS 实时系统搭建
    WeX5 IDE 手机移动开发+JAVA +大数据
    云计算高级运维工程师
    CentOS 5.8 上安装 systemtap-2.6
    SYSTEMTAP -ORACLE
    Apple激活日期查询
    Div 浮动到另一个div之上
    Python模块常用的几种安装方式
  • 原文地址:https://www.cnblogs.com/MrChuJiu/p/15322738.html
Copyright © 2020-2023  润新知