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
参考文献
上一篇: ruby 局部变量
下一篇: hive的概述和数据类型
推荐阅读
-
asp.net core系列 76 Apollo 快速安装模式下填坑和ASP.NetCore结合使用
-
asp.net core 系列 8 Razor框架路由(下)
-
asp.net core系列 47 Identity 自定义用户数据
-
asp.net core 系列之用户认证(1)-给项目添加 Identity
-
asp.net core系列 62 CQRS架构下Equinox开源项目分析
-
asp.net core系列 51 Identity 授权(下)
-
ASP.NET CORE系列【四】基于Claim登录授权
-
asp.net core 系列 11 配置configuration (下)
-
asp.net core系列 46 Identity介绍
-
asp.net core系列 48 Identity 身份模型自定义