在系统开发的时候一个老生常谈的权限管理问题,翻阅了很多的网络资料,但是总感觉离实际使用还有一段距离,其实权限控制无非就几个“请求、页面按钮、字段显示”, 对于前端权限就需要配合JS了, 这里主要展示我这些年来一直使用的一个关于权限管理的案例,如果你只是写一个简单的CMS系统,那么下面代码其实拷贝就可以用了,如果是需要进行较大型系统开发就需要进一步封装, 下面是我的思路,写的不好大家勿喷哈,有不同意见的留下一起探讨。
1、在MVC开发时路由中包含了我们所有请求信息(Controller、Action、URL全文),而MVC又提供了过滤器的机制,因此我们将权限管理封装到过滤其中。首先把每个Controller的继承封装一个BaseController,这个Controller基类可以编写一些直接调用的方法,例如Session等。
/// <summary> /// 系统基础控制器类 /// </summary> public abstract class BaseUIController : Controller { /// <summary> /// 页面初始化过程 /// </summary> protected override void Initialize(System.Web.Routing.RequestContext requestContext) { requestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache); base.Initialize(requestContext); } /// <summary> /// 内容返回 /// </summary> /// <param name="content">特定内容供JS参考是否含流程定义等动作。</param> /// <param name="contentType"></param> /// <param name="contentEncoding"></param> /// <returns></returns> protected override ContentResult Content(string content, string contentType, Encoding contentEncoding) { return base.Content(content, contentType, contentEncoding); } /// <summary> /// 登陆用户ID (Session存储) /// </summary> public long LoginedUserID { get { object UID = Ant.UI.Controls.SessionConfig.GetSession("UID"); if (Session == null || UID == null) return -1; else { return (long)UID; } } set { Ant.UI.Controls.SessionConfig.SetSession("UID", value); } } /// <summary> /// 获取URL参数值,返回 NULL 或 值 /// </summary> /// <param name="keyName">参数名</param> public string RequestUrlParams(string keyName) { if (Array.IndexOf(Request.QueryString.AllKeys, keyName) >= 0) return Request.QueryString[keyName].ToString(); else return null; } }
2、这个时候我们编写一个过滤器,在这个过滤器中可以在请求的Controller中获取controller名称和action名称。 有了这两个名称就能定位到具体的页面了,当然在得到页面之前我们可以判断用户是否已经登录。而页面权限页已经用数据库保存起来:A用户或R角色对某一个Controller/Action的页面(这个页面可能是新增信息、修改、删除信息的请求链接)是否有访问权限。
/// <summary> /// 用户登录过滤器 /// </summary> public class UserLoginedFilter : AuthorizeAttribute { public string name { get; set; } /// <summary> /// 页面授权过程(验证用户登录状态) /// </summary> /// <param name="filterContext"></param> public override void OnAuthorization(AuthorizationContext filterContext) { UI.Controllers.BaseUIController _ControllerObj = (UI.Controllers.BaseUIController)filterContext.Controller; string controllerStr = _ControllerObj.ControllerContext.RouteData.Values["controller"].ToString(); string actionStr = _ControllerObj.ControllerContext.RouteData.Values["action"].ToString(); //用户尚未登陆 或 登陆超时。 if (_ControllerObj.LoginedUserID == -1) { UserError.LoginError(); } // 权限验证 根据 Controller 与 Action(这里可以将权限缓存取出来进行用户匹配,如果被拒绝可以抛出异常) else if ( controllerStr.ToLower() == "admin" && actionStr.ToLower() == "login") { throw new HttpException("权限验证。" + _ControllerObj.ControllerContext.Controller.ToString()); } base.OnAuthorization(filterContext); } }
3、此时页面调用时就不用在每个Action中编写权限验证代码啦(有些权限验证的源码会在Action上增加过滤器,为了偷懒硬是想方设法把权限封装成直接在Controller类上添加一次过滤器就能完成的实现)
[UserLoginedFilter] public class AdminController : UI.Controllers.BaseUIController { /// <summary> /// 登陆(登陆页面不需要权限验证,增加AllowAnonymous特性) /// </summary> [AllowAnonymous] public ActionResult Login(FormCollection form) { return View(); } /// <summary> /// 主界面 /// </summary> public ActionResult Index() { return View(); } }
上面只是我在系统开发过程中对于权限管理的一个思路,也实实在在的应用到了一些系统中,当然上面这些代码只能勉强判断是否登陆,如果你需要对数据权限、页面权限、字段权限进行管理那么就需要进一步的扩展。如果需要在抛出异常后将异常信息友好的返回给客户端,那你仍然需要在Global中捕获返回状态码以及错误信息。因此我说这只是我的一个思路,路过的朋友给我建议。多谢!
原文地址:https://www.cnblogs.com/EvanYu/p/10556171.html