当前位置: 移动技术网 > IT编程>开发语言>.net > asp.net core系列 51 Identity 授权(下)

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

2019年04月10日  | 移动技术网IT编程  | 我要评论

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

 

  参考文献

    

    

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网