zoukankan      html  css  js  c++  java
  • 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), 来验证用户访问资源权限,条件是当前用户必需是924964690@qq.com,因为是该用户的文章
                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 = "924964690@qq.com", 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?}");

        最后当924964690@qq.com用户登录成功后,访问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

      参考文献

        基于资源的授权

        基于视图的授权

  • 相关阅读:
    android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 3
    display:inline-block的运用
    图解单片机8位PWM、16位PWM中“位”的含义!
    UVA10006
    [置顶] CF 86D Powerful array 分块算法入门,n*sqrt(n)
    俗人解释 三维渲染 在工作过程
    HDU 4414 Finding crosses(dfs)
    Codeforces 35E Parade 扫描线 + list
    hdu 4374 单调队列
    LeetCode OJ平台Sort Colors讨论主题算法
  • 原文地址:https://www.cnblogs.com/MrHSR/p/10675955.html
Copyright © 2011-2022 走看看