.Net MVC实现角色-API权限验证的一种方式
阅文时长 | | 1.15分钟 | 字数统计 | | 1844.8字符 |
主要内容 | | 1、引言&背景 2、部分设计分享 3、声明与参考资料 | ||
『.Net MVC实现角色-API权限验证的一种方式』 | |||
编写人 | | SCscHero | 编写时间 | | 2022/3/27 PM9:31 |
文章类型 | | 系列 | 完成度 | | 已完成 |
座右铭 | 每一个伟大的事业,都有一个微不足道的开始。 |
一、引言&背景 完成度:100%
a) 应对问题&背景
RBAC的权限设计已经应用到越来越多的系统中,然而在一些老项目中,对各个Role可访问的API并未做相关的限制,从而引发高级别的安全漏洞。这里介绍一种简单且比较可靠的设计。
b) 应用场景
- 在RBAC的权限设计中,对应的Role进行API权限检验。
c) 分析思路
- 首先对"Role-API"的对应关系进行梳理,一般用一张关系表进行存储。存储在缓存中。(缓存写入节点、过期时间按需而论),比如:博主是在项目启动的Global.asax文件中写入缓存,设置为永不过期,理由是项目功能已基本不迭代(当然这也有很多不便之处:例如如果按博主的这种方式,如果寄托于IIS,需要Stop后Start来更新缓存)。
- 新增一个特性AjaxAuthorizeAttribute继承于身份验证AuthorizeAttribute特性,重写OnAuthorization方法;写入逻辑为:用服务器端存储的当前用户的上下文信息中的Role取其可访问的API集合,再与访问接口的URL做判断,判断此Role是否具备该接口的权限,若不具备权限则返回403.cshtml的静态页;此特性用来标记需验证的控制器或Action。
- 以上这一种方式即可简单且相对可靠的实现对RBAC权限设计中,Role-API的权限校验。
二、部分设计分享 完成度:100%
a) Role-API存储关系表
以下是存储"Role-API"对应关系的关系表,如图博主是用了五个字段来存:步长为10主键ID、RoleID、RoleName、Url、APiDesc。其中RoleName和ApiDesc是冗余字段,方便开发者阅读设计的,在缓存中存的对象不需要存RoleName和ApiDesc。
![](https://img-blog.csdnimg.cn/483cd27b564f433ea8e8e59615b87814.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAU0NzY0hlcm8=,size_20,color_FFFFFF,t_70,g_se,x_16)
其中有一点需要注意的是URL,一般都是维护成/Area/Controller/Action。
b) AjaxAuthorizeAttribute
AjaxAuthorizeAttribute是自定义的重写身份验证特性的类。以下为一个通用设计。其中需要注意的是第2步骤,在取AuthorizationContext中的请求路由时,有几种取数方式,注意区别。在以下代码示例中有一些解释可以参考。
public class AjaxAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
//1. 从缓存中取数据的Obj对象,并将Obj转换为实体对象。(转换方式是否最优有待思考优化,先不做讨论)
IList objList = (IList)CacheDataLogic.CacheHelper.GetData(ParameterNames.CacheRoleResourceAll);
var res = objList.Cast<MMC_RoleResourceMap>();
//ApplicationContext是我们封装的取用户上下文的类
var RoleName = ((RoleModel)CacheDataLogic.CacheHelper.GetData(ParameterNames.CacheClientUserRole + ApplicationContext.Current.LoginUserInfo.UserModel.UserID)).RoleName;
//2. 取当前用户API集合是否包含请求集合。
//filterContext.HttpContext.Request.RawUrl//路由后带参数,取到的数据是带参数的。比如:/SCscCon/SCscAction?scsc=6666。
//filterContext.HttpContext.Request.Path//可以过滤掉?后的参数,比如:/Claim/SCscAction /?scsc=4430。但无法解决不带?的参数URL。比如: /Claim/ClaimApply/4430
var spA = filterContext.HttpContext.Request.Path.Split('/');//如果上一种不是想用来判断的参数,可以做截取。比如下面这样。
//3. 判断当前用户API集合是否包含请求集合。
if (res.Where(o => o.RoleName == RoleName && o.Url == ("/" + spA[1] + "/" + spA[2])).Count() > 0)
{
base.OnAuthorization(filterContext);
}
else
{
HttpContext.Current.Response.Redirect("~/AuthorizeError.html");
return;
}
}
}
另外建议大家可以了解一下AuthorizeAttribute对象,其中的各方法的调用顺序可以研究研究,比如HandleUnauthorizedRequest方法等等,都是需要掌握的知识点。
c) 非授权通用页
用来重定向的通用页html代码,记录一下,后面方便复用。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<hgroup>
<h1>Error.</h1>
<h2>An error occurred while processing your request.</h2>
</hgroup>
</body>
</html>
三、声明与参考资料 完成度:100%
原创博文,未经许可请勿转载。
如有帮助,欢迎点赞、收藏、关注。如有问题,请评论留言!如需与博主联系的,直接博客私信SCscHero即可。