我们在做项目项目,经常会碰到权限体系,权限体系属于系统架构的一个最底层的功能,也是非常重要的功能,几乎在每个项目都会用到。那么我们该如何设计一个比较合理的且扩展性较强的权限体系呢?
经过多天的摸索,参考多个系统以及自己的经验,《沐雪微店系统 NetCore3.1》的权限体系是这样的。
其中:
1、用户与角色是1对多关系( 1个用户只有1个角色,1个角色可以对应多个用户);
2、角色与权限组是1对1关系( 1个角色只有1个权限组,1个权限组只有1个角色)。
3、一个权限组里包含1个菜单和多个操作按钮;
4、操作按钮预先定义好最多的情况的枚举值;(比如 查看,新增,修改,删除,审核,下载,确认,回复)
这样的架构,相对来说比较合理,适合绝大多数系统使用了。(设计的越灵活,控制起来越困难,越困难越容易出现错误,所以要根据实际的情况控制灵活到什么程度即可;不要一口吃成胖子,想要一次性搞出无限灵活的权限系统。)
1、菜单的增删改查;
2、权限组的增删改查:
3、用户的增删改查:
大家在菜单管理页面,应该注意到有3个字段:--编码,链接地址和权限值;这些是我们写代码的时候需要用的。
1、创建一个控制器的父类--BaseController,这里只要有一个可以获取当前登录者的方法即可,类似如下代码:
/// <summary>
/// 当前登录者
/// </summary>
public PTLoginResp CurrentUser
{
get
{
PTLoginResp currentUser = new PTLoginResp();
if (User.Identity.IsAuthenticated)
{
var claimIdentity = (ClaimsIdentity)User.Identity;
string key = claimIdentity.FindFirst("tokenid").Value;
currentUser.id = LoginCredentials.PFDecodeRedisKeyOfUserId(key);
currentUser.user\_name = claimIdentity.FindFirst("user\_name").Value;
currentUser.real\_name = claimIdentity.FindFirst("real\_name").Value;
currentUser.mobile\_phone = claimIdentity.FindFirst("mobile\_phone").Value;
currentUser.role\_id = ConvertHelper.LongParse(claimIdentity.FindFirst("role\_id").Value, );
}
return currentUser;
}
}
2、创建具体的业务控制器和相应的Action,并且集成BaseController;
3、创建一个Action的权限属性特性方法,比如下面代码:
/// <summary>
/// Action的权限属性
/// </summary>
\[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)\]
public class ActionAuthDescriptorAttribute : System.Attribute
{
public ActionAuthDescriptorAttribute(string NavCode, AuthTypeEnum AuthType)
{
this.NavCode = NavCode;
this.AuthType = AuthType;
}
/// <summary>
/// 权限组code
/// </summary>
public string NavCode { get; set; }
/// <summary>
/// 权限操作的枚举值,比如Show
/// </summary>
public AuthTypeEnum AuthType { get; set; }
}
这样,我们就可以在Action上加上这个特性了:
/// <summary>
/// 《沐雪微店系统 Netcore 3.1》添加管理员页面
/// </summary>
/// <returns></returns>
\[ActionAuthDescriptor("manager\_mgr", AuthTypeEnum.Add)\]
public async Task< ActionResult> Create()
{
ManagerInfo managerAdd = new ManagerInfo();
managerAdd.using\_type = UsingTypeEnum.sys.ToString();
managerAdd.is\_lock = false;
List<muxue\_role> roleList =await \_roleService.GetRoleList(UsingTypeEnum.sys);
roleList = roleList.FindAll(p => p.is\_sys == false);
ViewBag.roleList = roleList;
return View(managerAdd);
}
4、开始写权限验证过滤器了PrivilegeFilter:
验证的大概逻辑如下:
///
///
重点的代码如下:
public override void OnActionExecuting(ActionExecutingContext context)
{
var controller = context.Controller as BaseController;
if (controller == null)
{
base.OnActionExecuting(context);
return;
}
if (controller.CurrentUser == null)
{
//《沐雪微店系统 Netcore 3.1》去登录
// context.HttpContext.ChallengeAsync().Wait();
base.OnActionExecuting(context);
return;
}
string requestMethod = context.HttpContext.Request.Method.ToLower();
ControllerActionDescriptor ad = context.ActionDescriptor as ControllerActionDescriptor;
bool isControllerAllRights = ad.ControllerTypeInfo.IsDefined(typeof(AllRightsAttribute), false);
bool isActionAllRights = ad.MethodInfo.IsDefined(typeof(AllRightsAttribute), false);
bool isActionAuthDescriptor = ad.MethodInfo.IsDefined(typeof(ActionAuthDescriptorAttribute), false);
if (!isControllerAllRights && !isActionAllRights && !isActionAuthDescriptor)
{
//没有权限访问
if (requestMethod == "get")
{
context.Result = new RedirectResult("/Error/Index?msg=没有权限");
base.OnActionExecuting(context);
return;
}
else
{
context.Result = new JsonResult(NoPrivPostJsonResult());
base.OnActionExecuting(context);
return;
}
}
if (isActionAllRights)
{
base.OnActionExecuting(context);
return;
}
if (isControllerAllRights && !isActionAllRights && !isActionAuthDescriptor)
{
base.OnActionExecuting(context);
return;
}
if (isActionAuthDescriptor)
{
var authorizeAttr = ad.MethodInfo.GetCustomAttributes(typeof(ActionAuthDescriptorAttribute), false).FirstOrDefault() as ActionAuthDescriptorAttribute;
string navCode = authorizeAttr.NavCode;
AuthTypeEnum authType = authorizeAttr.AuthType;
long current\_role\_id = controller.CurrentUser.role\_id;
bool hasRolePriv = \_roleprivilegeService.HasRolePriv(current\_role\_id, navCode, authType).Result;
if (!hasRolePriv)
{//没有权限
if (requestMethod == "get")
{
context.Result = new RedirectResult("/Error/Index?msg=没有权限");
base.OnActionExecuting(context);
return;
}
else
{
context.Result = new JsonResult(NoPrivPostJsonResult());
base.OnActionExecuting(context);
return;
}
}
}
base.OnActionExecuting(context);
}
将这个Filter添加到StartUp里:
services.AddMvc(options =>
{
if (!env.IsDevelopment())
{
}
options.Filters.Add<LogstashFilter>();
options.Filters.Add<PrivilegeFilter>();//权限验证
options.Filters.Add<XcActionFilter>();
options.Filters.Add<GlobalExceptions>();
})
这样就完成了权限控制了。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章