1.6 基于资源的授权
前面二篇中,熟悉了五种授权方式(对于上篇讲的策略授权,还有IAuthorizationPolicyProvider的自定义授权策略提供程序没有讲,后面再补充)。本篇讲的授权方式不是一种全新的授权方式,而是授权应用场景的灵活控制。
基于资源的授权是控制在 razor pages处理程序或mvc的action之中。资源:比如作者发表的文章,只有该作者才能更新文章,文章在进行授权评估之前,必须从数据存储中检索文章。
(1) 引用 IAuthorizationService 授权服务
授权作为实现IAuthorizationService服务并注册到服务集合的Startup类。 下面在mvc action中引用该接口,准备进行授权控制。
public class DocumentController : Controller { private readonly IAuthorizationService _authorizationService; private readonly IDocumentRepository _documentRepository; public DocumentController(IAuthorizationService authorizationService, IDocumentRepository documentRepository) { _authorizationService = authorizationService; _documentRepository = documentRepository; } }
IAuthorizationService接口有二个AuthorizeAsync
方法重载:
//重载1:指定资源resource和策略需求列表 Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements); //重载2:指定资源resource和策略名称 Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);
(2) 授权需求定义
基于 CRUD (创建、 读取、 更新、 删除) 的授权操作,使用OperationAuthorizationRequirement帮助器类,来提供一些授权名称。
/// <summary> ///授权四种需求Crud /// </summary> public static class Operations { public static OperationAuthorizationRequirement Create = new OperationAuthorizationRequirement { Name = nameof(Create) }; public static OperationAuthorizationRequirement Read = new OperationAuthorizationRequirement { Name = nameof(Read) }; public static OperationAuthorizationRequirement Update = new OperationAuthorizationRequirement { Name = nameof(Update) }; public static OperationAuthorizationRequirement Delete = new OperationAuthorizationRequirement { Name = nameof(Delete) }; }
(3) 定义处理程序
/// <summary> /// 接口AuthorizationHandler<TRequirement, TResource> /// 使用OperationAuthorizationRequirement需求和Document资源 /// </summary> public class DocumentAuthorizationCrudHandler: AuthorizationHandler<OperationAuthorizationRequirement, Document> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement, Document resource) { //登录的当前用户是该文章作者,并且有读取权限。实际开发中从数据库读取TResource资源和requirement需求(需求这里是CRUD权限) //动态获取时,可以基于用户声明表UserClaim,也可以基于角色声明表RoleClaim,使用context.User.HasClaim 来判断 if (context.User.Identity?.Name == resource.Author && requirement.Name == Operations.Read.Name) { context.Succeed(requirement); } return Task.CompletedTask; } }
(4) Action中使用AuthorizeAsync验证授权
当用户登录后,要访问该文章页面时(/Document/index/1),使用AuthorizeAsync方法进行调用,确定当前用户是否允许查看提供的文章.
/// <summary> /// /Document/index/1 /// </summary> /// <param name="documentId"></param> /// <returns></returns> public async Task<IActionResult> Index(int documentId) { Document Document = _documentRepository.Find(documentId); if (Document == null) { return new NotFoundResult(); } //使用AuthorizeAsync重载方法(1), 来验证用户访问资源权限,条件是当前用户必需是924964690@qq.com,因为是该用户的文章 var author