zoukankan      html  css  js  c++  java
  • 十、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);
            }
    
  • 相关阅读:
    Get distinct count of rows in the DataSet
    单引号双引号的html转义符
    PETS Public English Test System
    Code 39 basics (39条形码原理)
    Index was outside the bounds of the array ,LocalReport.Render
    Thread was being aborted Errors
    Reportviewer Error: ASP.NET session has expired
    ReportDataSource 值不在预期的范围内
    .NET/FCL 2.0在Serialization方面的增强
    Perl像C一样强大,像awk、sed等脚本描述语言一样方便。
  • 原文地址:https://www.cnblogs.com/MrChuJiu/p/15322738.html
Copyright © 2011-2022 走看看