asp.net core系列 51 Identity 授权(下)

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), 来验证用户访问资源权限,条件是当前用户必需是[email protected],因为是该用户的文章
            var authorizationResult = await _authorizationService.AuthorizeAsync(User, Document, Operations.Read);

            //如果授权成功,则返回查看文档的页面
            if (authorizationResult.Succeeded)
            {
                return View();
            }
            //用户已通过身份验证,但授权失败
            else if (User.Identity.IsAuthenticated)
            {
                return new ForbidResult();
            }
            else
            {
                //Challenge:怀疑,返回重新执行身份认证,重定向到登录页
                return new ChallengeResult();
            }
        }

  (5) Document实体的定义和该实体仓储

    public class Document
    {
        public string Author { get; set; }

        public byte[] Content { get; set; }

        public int ID { get; set; }

        public string Title { get; set; }
    }
    public class DocumentRepository : IDocumentRepository
    {
        public Document Find(int documentId)
        {
            return new Document
            {
                Author = "[email protected]",
                Content = null,
                ID = documentId,
                Title = "Test Document"
            };
        }
    }

    public interface IDocumentRepository
    {
        Document Find(int documentId);
    }    

  (6) 添加路由规则,和注入IAuthorizationService服务

    services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
   routes.MapRoute(
                   name: "document",
                   template: "{controller=Document}/{action=Index}/{documentId?}");

    最后当[email protected]用户登录成功后,访问Document/index/1,查看该文章成功。

  总结:基于资源的授权,是应用在mvc的action 中或razor pages处理程序中,是区别之前的几种授权方式, 因为之前讲的授权是:启动程序时授权文件或文件夹,在控制器 action 和PageModel之上应用[Authorize]特性。

       对于AuthorizeAsync重载方法(2)的使用案例查看官网文档,这里不在介绍。

  思考:在实际开发项目中,处理资源如(增、删、改、查)权限,可以考虑本篇的基于资源的授权,但上面的示例需要改进,因为示例中定义的处理程序只针对Document资源,以及需求(指权限)是写死在处理程序中。如果要实现通用的资源授权,资源和需求权限需要从数据库中获取。例如考虑如下修改:

         //定义通用的TResource
         public class  AuthorizationResource
           {
              public string UrlResource{get;set;}
           }
       //在index的action中修改
         .AuthorizeAsync(User, new AuthorizationResource (){UrlResource="/Document/index/1" }, Operations.Read);
      //处理程序修改,省略了授权逻辑处理(数据库获取需求和资源)
         public class DocumentAuthorizationCrudHandler: AuthorizationHandler<OperationAuthorizationRequirement, AuthorizationResource >

    

1.7 基于视图的授权    

  在项目开发中,授权权限还需要控制页面,对页面的html进行显示或隐藏。需要在页面上使用授权服务依赖关系注入,若要将授权服务注入到 Razor 视图中,使用@inject指令。如果希望每个视图都能使用授权服务,需要将@inject指令插入 _ViewImports.cshtml的文件视图中。下面的视图授权控制是基于资源的授权

    @using Microsoft.AspNetCore.Authorization
    @inject IAuthorizationService AuthorizationService
    <!--  指定策略名称  !-->
  @if ((await AuthorizationService.AuthorizeAsync(User, "PolicyName")).Succeeded)
  {
      <p>This paragraph is displayed because you fulfilled PolicyName.</p>
  }
    <!--  Model是指TResource !-->
   @if ((await AuthorizationService.AuthorizeAsync(User, Model, Operations.Edit)).Succeeded)
  {
      <p><a class="btn btn-default" role="button"
          href="@Url.Action("Edit", "Document", new { id = Model.Id })">Edit</a></p>
  }

  总结:视图中授权控制不能保证权限安全,还需要在action中实现授权服务。开源Github

  参考文献

    基于资源的授权

    基于视图的授权

原文地址:https://www.cnblogs.com/MrHSR/p/10675955.html

时间: 2024-11-07 15:25:19

asp.net core系列 51 Identity 授权(下)的相关文章

asp.net core系列 48 Identity 身份模型自定义

原文:asp.net core系列 48 Identity 身份模型自定义 一.概述 ASP.NET Core Identity提供了一个框架,用于管理和存储在 ASP.NET Core 应用中的用户帐户. Identity添加到项目时单个用户帐户选择作为身份验证机制. 默认情况下,Identity可以使用的 Entity Framework (EF) Core 数据模型. 本文介绍如何自定义的身份标识模型. 1.1 下面是已经存在的身份模型, 由以下实体类型组成: 实体类型 说明 关系 Use

asp.net core系列 46 Identity介绍

一. Identity 介绍 ASP.NET Core Identity是一个会员系统,可为ASP.NET Core应用程序添加登录功能.可以使用SQL Server数据库配置身份以存储用户名,密码和配置文件数据.或者,可以使用另一个持久性存储,例如,Azure表存储.下面学习如何使用Identity注册,登录以及基架标识. 1.1 Identity搭建演示 下面使用vs 2017来演示: 1.选择“文件” > “新建” > “项目”. 2.选择“ASP.NET Core Web应用程序”. 

asp.net core 系列 11 配置configuration (下)

四. 文件配置提供程序AddIniFile. AddXmlFile.AddJsonFile FileConfigurationProvider 是从文件系统加载配置的基类. 以下配置提供程序专用于特定文件类型: (1) INI 配置提供程序 IniConfigurationProvider: FileConfigurationProvider (2) JSON 配置提供程序 JsonConfigurationProvider: FileConfigurationProvider (3) XML

asp.net core系列 47 Identity 自定义用户数据

一.概述 接着上篇的WebAppIdentityDemo项目,将自定义用户数据添加到Identity DB,自定义扩展的用户数据类应继承IdentityUser类, 文件名为Areas / Identity / Data / {项目名称}User.cs.自定义的用户数据模型属性需要使用[PersonalData]来修饰,以便自动下载和删除.使数据能够下载和删除有助于满足GDPR要求. 1.1 自定义用户数据类 WebAppIdentityDemo.Areas.Identity.Data. pub

asp.net core 系列 14 错误处理

一.概述 本文介绍处理 ASP.NET Core 应用中常见错误的一些方法.主要是关于:开发环境异常页:非开发环境配置自定义异常处理页:配置状态代码页(没有正文响应,http状态400~599的). 1.1 开发环境异常页 要将应用配置为显示有关异常的详细信息的页面,请使用开发环境异常页.要环境设置为 Development,具体查看:asp.net core系列9环境.下面向 Startup.Configure 方法添加代码行: if (env.IsDevelopment()) { //注意:

asp.net core系列 55 IS4使用Identity密码保护API

原文:asp.net core系列 55 IS4使用Identity密码保护API 一.概述 OAuth 2.0资源(web api)所有者密码授权,允许客户端(Client项目)向令牌服务(IdentityServer项目)发送用户名和密码,并获取代表该用户的访问令牌.在官方文档中讲到:规范通常建议不要使用“资源所有者密码授权”.当用户进行身份验证并请求访问令牌时,使用一个交互式OpenID Connect流程通常要好得多(下篇再了解). 本篇介绍“资源所有者密码授权”是因为这种授权允许我们快

asp.net core 系列 8 Razor框架路由(下)

三.页面路由操作约定 接着上篇讲asp.net core 系列 7 Razor框架路由.在上篇继续第三节 "页面路由操作约定" 的最后一小节 AddPageRoute . 3.3. 配置页面路由AddPageRoute 使用 AddPageRoute 配置路由,该路由与指定页面关联, 使用指定的路由生成页面链接. AddPageRoute 使用 AddPageRouteModelConvention 建立路由. 示例应用为 Privacy.cshtml 创建指向 /ThePrivacy

asp.net core 系列 15 中间件

原文:asp.net core 系列 15 中间件 一.概述 中间件(也叫中间件组件)是一种装配到应用管道以处理请求和响应的软件. 每个组件:(1)选择是否将请求传递到管道中的下一个组件;(2)可以在管道中的下一个组件之前和之后执行工作. 请求委托用于生成请求管道. 请求委托会处理每个 HTTP 请求.使用以下方法配置请求委托:Run,  Map, Use扩展方法.可以将单个请求委托作为匿名方法(称为内联中间件in-line middleware) 或者可以在可重用类中定义.这些可重用的类和内联

asp.net core系列 30 EF管理数据库架构--必备知识 迁移

原文:asp.net core系列 30 EF管理数据库架构--必备知识 迁移 一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为准,请使用迁移. 对 EF Core 模型进行更改时,此方法会以增量方式将相应架构更改应用到数据库,以使数据库保持与 EF Core 模型兼容.  (2)如果希望以数据库架构为准,请使用反向工程. 使用此方法,可通过将数