介绍

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

权限配置和使用

官方地址: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);
}

十、Abp vNext 基础篇丨权限的更多相关文章

  1. 六、Abp vNext 基础篇丨文章聚合功能上

    介绍 9月开篇讲,前面几章群里已经有几个小伙伴跟着做了一遍了,遇到的问题和疑惑也都在群里反馈和解决好了,9月咱们保持保持更新.争取10月份更新完基础篇. 另外番外篇属于 我在abp群里和日常开发的问题 ...

  2. 十一、Abp vNext 基础篇丨测试

    前言 祝大家国庆快乐,本来想国庆之前更新完的,结果没写完,今天把剩下的代码补了一下总算ok了. 本章节也是我们后端日常开发中最重要的一步就是测试,我们经常听到的单元测试.集成测试.UI测试.系统测试, ...

  3. Abp vNext 基础篇丨分层架构

    介绍 本章节对 ABP 框架进行一个简单的介绍,摘自ABP官方,后面会在使用过程中对各个知识点进行细致的讲解. 领域驱动设计 领域驱动设计(简称:DDD)是一种针对复杂需求的软件开发方法.将软件实现与 ...

  4. 七、Abp vNext 基础篇丨文章聚合功能下

    介绍 不好意思这篇文章应该早点更新的,这几天在忙CICD的东西没顾得上,等后面整好了CICD我也发2篇文章讲讲,咱们进入正题,这一章来补全剩下的 2个接口和将文章聚合进行完善. 开工 上一章大部分业务 ...

  5. Abp vNext 基础篇丨领域构建

    介绍 我们将通过例⼦介绍和解释⼀些显式规则.在实现领域驱动设计时,应该遵循这些规则并将其应⽤到解决⽅案中. 领域划分 首先我们先对比下Blog.Core和本次重构设计上的偏差,可以看到多了一个博客管理 ...

  6. 五、Abp vNext 基础篇丨博客聚合功能

    介绍 业务篇章先从客户端开始写,另外补充一下我给项目起名的时候没多想起的太随意了,结果后面有些地方命名冲突了需要通过手动using不过问题不大. 开工 应用层 根据第三章分层架构里面讲到的现在我们模型 ...

  7. 八、Abp vNext 基础篇丨标签聚合功能

    介绍 本章节先来把上一章漏掉的上传文件处理下,然后实现Tag功能. 上传文件 上传文件其实不含在任何一个聚合中,它属于一个独立的辅助性功能,先把抽象接口定义一下,在Bcvp.Blog.Core.App ...

  8. 九、Abp vNext 基础篇丨评论聚合功能

    介绍 评论本来是要放到标签里面去讲的,但是因为上一章东西有点多了,我就没放进去,这一章单独拿出来,内容不多大家自己写写就可以,也算是对前面讲解的一个小练习吧. 相关注释我也加在代码上面了,大家看看代码 ...

  9. Django基础篇--用户权限管理和组管理

    Django作为一个成熟的python后台开发框架,为开发者提供了很多内置的功能,开发者只需要做一些配置就可以完成原生操作中比较复杂的代码编写.这些内置功能中其中一个比较强大的功能就是后台用户管理类. ...

随机推荐

  1. Linux中DNS分离解析

    目录 一.分离解析概述 二.DNS分离解析实验 要求 实验步骤 一.分离解析概述 分离解析:同一个dns服务器,同一个域名情况下,不同网段进行访问会解析出不同的IP地址 分离解析的域名服务器实际也是主 ...

  2. 过去,我买漫画看;现在,我用Python爬虫来看

    原标题:运用Python多线程爬虫下载漫画 前言: 以前,我都是买漫画书看的,那个时候没有电脑.今天,我到网上看了一下,发现网上提供漫画看,但是时时需要网络啊!为什么不将它下载下来呢!  1.怎样实现 ...

  3. 神经网络:numpy实现神经网络框架

    欢迎访问个人博客网站获取更多文章: https://beityluo.space 本文用numpy从零搭建了一个类似于pytorch的深度学习框架 可以用于前面文章提到的MINST数据集的手写数字识别 ...

  4. 微信小程序开发——后端Java(一)

    一.前言 最近接触了小程序的开发,后端选择Java,因为小程序的代码运行在腾讯的服务器上,而我们自己编写的Java代码运行在我们自己部署的服务器上,所以一开始不是很明白小程序如何与后台进行通信的,然后 ...

  5. Android模块化开发实践

    一.前言 随着业务的快速发展,现在的互联网App越来越大,为了提高团队开发效率,模块化开发已经成为主流的开发模式.正好最近完成了vivo官网App业务模块化改造的工作,所以本文就对模块化开发模式进行一 ...

  6. Spring系列之多个数据源配置

    前言 在上篇文章讲到了如何配置单数据源,但是在实际场景中,会有需要配置多个数据源的场景,比如说,我们在支付系统中,单笔操作(包含查询.插入.新增)中需要操作主库,在批量查询或者对账单查询等对实时性要求 ...

  7. Python小白的数学建模课-18.最小生成树问题

    最小生成树(MST)是图论中的基本问题,具有广泛的实际应用,在数学建模中也经常出现. 路线设计.道路规划.官网布局.公交路线.网络设计,都可以转化为最小生成树问题,如要求总线路长度最短.材料最少.成本 ...

  8. java一些工具类

    import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java. ...

  9. VMware ESXi 7.0 U2 SLIC & Unlocker Intel NUC 专用镜像 202109 更新

    2021.08.31 更新:集成 "vmkusb-nic-fling" 和 "nvme-community",现在只有一个镜像. 2021.06.16 更新:集 ...

  10. yum命令报错File "/usr/bin/yum", line 30 except KeyboardInterrupt, e:

    使用yum命令报错File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: 问题出现原因:yum包管理是使用python2 ...