http://www.cnblogs.com/wuhuacong/p/3361351.html

我在上一篇随笔《基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍》中大概介绍了基于MVC的Web开发框架的权限控制总体思路。其中的权限控制就是分为“用户登录身份验证”、“控制器方法权限控制”、“界面元素权限控制”三种控制方式,可以为Web开发框架本身提供了很好用户访问控制和权限控制,使得用户界面呈现菜单、Web界面的按钮和内容、Action的提交控制,均能在总体权限功能分配和控制之下。

本篇文章主要细化这三个方面的介绍,重点介绍“控制器方法权限控制”、“界面元素权限控制”这两种权限控制方式。

1、用户登录控制

登录界面如下所示。

其中登录的前台页面代码如下所示,其中可以在登录界面接收验证码(如果必要的话)。

        //实现用户登录function LoginUserInfo() {//获取单击用户登录按钮的事件$("#btnLogin").click(function () {//首先获取到要传递到控制器的参数,并且狗造成Json。UserName,UserPassword,Codevar postData = {UserName: $("#UserName").val(),Password: $("#Password").val(),Code: $("#Code").val()};//发送异步请求实现登录 ajax$.ajax({url: '/Login/CheckUser',data: postData,cache: false,async: true,type: 'post',success: function (data) {if (data == "OK") {window.location.href = "/Home/Index";} else {alert(data);window.location.href = "/Login/Index";}}});});}

用户登录的后台控制器方法如下所示:

        /// <summary>/// 对用户登录的操作进行验证/// </summary>/// <param name="username">用户账号</param>/// <param name="password">用户密码</param>/// <param name="code">验证码</param>/// <returns></returns>public ActionResult CheckUser(string username, string password, string code){string result = "";bool codeValidated = true;if (this.TempData["ValidateCode"] != null){codeValidated = (this.TempData["ValidateCode"].ToString() == code);}if (string.IsNullOrEmpty(username)){result = "用户名不能为空";}else if (!codeValidated){result = "验证码输入有误";}else{string ip = GetClientIp();string macAddr = "";string identity = BLLFactory<WHC.Security.BLL.User>.Instance.VerifyUser(username, password, MyConstants.SystemType, ip, macAddr);if (!string.IsNullOrEmpty(identity)){UserInfo info = BLLFactory<WHC.Security.BLL.User>.Instance.GetUserByName(username);if (info != null){result = "OK";Session["UserInfo"] = info;Session["Identity"] = info.Name.Trim();#region 取得用户的授权信息,并存储在Session中List<FunctionInfo> functionList = BLLFactory<Function>.Instance.GetFunctionsByUser(info.ID, MyConstants.SystemType);Dictionary<string, string> functionDict = new Dictionary<string, string>();foreach (FunctionInfo functionInfo in functionList){if (!string.IsNullOrEmpty(functionInfo.ControlID) &&!functionDict.ContainsKey(functionInfo.ControlID)){functionDict.Add(functionInfo.ControlID, functionInfo.ControlID);}}Session["Functions"] = functionDict;#endregion}}else{result = "用户名输入错误或者您已经被禁用";}}return Content(result);}

从上面的代码,我们可以看到,在用户登录成功后,后台把用户信息、用户权限列表信息放到了Session里面,方便进行后面的权限控制。

然后当前端页面获得成功响应并切换到Home的Index视图前,后台会调用Home的控制器,把一些用户信息放到了ViewBag对象里面,并构造用户的相关菜单项目,代码如下所示。

    public class HomeController : BaseController{public ActionResult Index(){if (CurrentUser != null){ViewBag.FullName = CurrentUser.FullName;ViewBag.Name = CurrentUser.Name;StringBuilder sb = new StringBuilder();List<MenuInfo> menuList = BLLFactory<Menu>.Instance.GetTopMenu(MyConstants.SystemType);int i = 0;foreach (MenuInfo menuInfo in menuList){sb.Append(GetMenuItemString(menuInfo, i));i++;}ViewBag.HeaderScript = sb.ToString();//一级菜单代码}return View();            }

2、控制器方法权限控制

我们知道,对页面的权限控制,可以分为前端控制和后台代码的控制,控制器方法的权限控制属于后台代码的控制。为了方便基类代码的权限控制,我们定义一个权限控制键的类,用来记录通用的增加、修改、删除、查看、列表、导出等传统控制元素,代码如下所示。

    /// <summary>/// 定义常用功能的控制ID,方便基类控制器对用户权限的控制/// </summary>[DataContract][Serializable]public class AuthorizeKey{#region 常规功能控制ID/// <summary>/// 新增记录的功能控制ID/// </summary>public string InsertKey { get; set; }/// <summary>/// 更新记录的功能控制ID/// </summary>public string UpdateKey { get; set; }/// <summary>/// 删除记录的功能控制ID/// </summary>public string DeleteKey { get; set; }/// <summary>/// 查看列表的功能控制ID/// </summary>public string ListKey { get; set; }/// <summary>/// 查看明细的功能控制ID/// </summary>public string ViewKey { get; set; }/// <summary>/// 导出记录的功能控制ID/// </summary>public string ExportKey { get; set; } #endregion#region 常规权限判断/// <summary>/// 判断是否具有插入权限/// </summary>public bool CanInsert { get; set; }/// <summary>/// 判断是否具有更新权限/// </summary>public bool CanUpdate { get; set; }/// <summary>/// 判断是否具有删除权限/// </summary>public bool CanDelete { get; set; }/// <summary>/// 判断是否具有列表权限/// </summary>public bool CanList { get; set; }/// <summary>/// 判断是否具有查看权限/// </summary>public bool CanView { get; set; }/// <summary>/// 判断是否具有导出权限/// </summary>public bool CanExport { get; set; }#endregion/// <summary>/// 默认构造函数/// </summary>public AuthorizeKey() { }/// <summary>/// 常用构造函数/// </summary>public AuthorizeKey(string insert, string update, string delete, string view = "") {this.InsertKey = insert;this.UpdateKey = update;this.DeleteKey = delete;this.ViewKey = view;}}

有了这个实体类,我们就可以在控制器的基类BaseController里面实现一些控制逻辑了。首先我们在控制器每次执行方法前,都对权限进行一个转换,并把控制键存储到ViewBage里面,方便前端页面的控制,如下代码所示。

        /// <summary>/// 重新基类在Action执行之前的事情/// </summary>/// <param name="filterContext">重写方法的参数</param>protected override void OnActionExecuting(ActionExecutingContext filterContext){base.OnActionExecuting(filterContext);//得到用户登录的信息CurrentUser = Session["UserInfo"] as UserInfo;            if (CurrentUser == null){Response.Redirect("/Login/Index");//如果用户为空跳转到登录界面}//设置授权属性,然后赋值给ViewBag保存
            ConvertAuthorizedInfo();ViewBag.AuthorizeKey = AuthorizeKey;}

其中ConvertAuthorizedInfo()函数是验证登陆用户是否具有相应的权限的。

        /// <summary>/// 对AuthorizeKey对象里面的操作权限进行赋值,用于页面判断/// </summary>protected virtual void ConvertAuthorizedInfo(){//判断用户权限AuthorizeKey.CanInsert = HasFunction(AuthorizeKey.InsertKey);AuthorizeKey.CanUpdate = HasFunction(AuthorizeKey.UpdateKey);AuthorizeKey.CanDelete = HasFunction(AuthorizeKey.DeleteKey);AuthorizeKey.CanView = HasFunction(AuthorizeKey.ViewKey);AuthorizeKey.CanList = HasFunction(AuthorizeKey.ListKey);AuthorizeKey.CanExport = HasFunction(AuthorizeKey.ExportKey);}

其中BaseController的控制器基类还定义了判断用户是否有某些权限的逻辑,如果没有没有权限,就会抛出自定义异常(MyDenyAccessException),代码如下。

        /// <summary>/// 用于检查方法执行前的权限,如果未授权,返回MyDenyAccessException异常/// </summary>/// <param name="functionId"></param>protected virtual void CheckAuthorized(string functionId){if(!HasFunction(functionId)){string errorMessage = "您未被授权使用该功能,请重新登录测试或联系管理员进行处理。";throw new MyDenyAccessException(errorMessage);}}

有了上面的这些逻辑,我们在业务控制器基类(BusinessController<B, T>)里面,就可以实现对一些基本操作的API的权限控制了。

    /// <summary>/// 本控制器基类专门为访问数据业务对象而设的基类/// </summary>/// <typeparam name="B">业务对象类型</typeparam>/// <typeparam name="T">实体类类型</typeparam>public class BusinessController<B, T> : BaseControllerwhere B : classwhere T : WHC.Framework.ControlUtil.BaseEntity, new(){/// <summary>/// 插入指定对象到数据库中/// </summary>/// <param name="info">指定的对象</param>/// <returns>执行操作是否成功。</returns>public virtual ActionResult Insert(T info){//检查用户是否有权限,否则抛出MyDenyAccessException异常base.CheckAuthorized(AuthorizeKey.InsertKey);bool result = false;if (info != null){result = baseBLL.Insert(info);}return Content(result);}/// <summary>/// 更新对象属性到数据库中/// </summary>/// <param name="info">指定的对象</param>/// <param name="id">主键ID的值</param>/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>public virtual ActionResult Update(string id, FormCollection formValues){//检查用户是否有权限,否则抛出MyDenyAccessException异常base.CheckAuthorized(AuthorizeKey.UpdateKey);T obj = baseBLL.FindByID(id);if (obj != null){//遍历提交过来的数据(可能是实体类的部分属性更新)foreach (string key in formValues.Keys){string value = formValues[key];System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(key);if (propertyInfo != null){try{// obj对象有key的属性,把对应的属性值赋值给它(从字符串转换为合适的类型)//如果转换失败,会抛出InvalidCastException异常propertyInfo.SetValue(obj, Convert.ChangeType(value, propertyInfo.PropertyType), null);}catch { }}}}bool result = baseBLL.Update(obj, id);return Content(result);}

3、界面元素权限控制

我们从上面那个Web开发框架的主界面图可以看到,里面对于某个特定的业务,增加、修改、、查看、删除等操作都放在了EasyUI的DataGrid工具栏里面了,为了动态控制用户能访问的界面按钮,我们需要结合用户权限集合进行界面呈现,首先我们把ToolBar放到一个层里面进行定义,如下代码所示。

        //实现对DataGird控件的绑定操作function InitGrid(queryData) {$('#grid').datagrid({   //定位到Table标签,Table标签的ID是gridurl: '/Information/FindWithPager',   //指向后台的Action来获取当前用户的信息的Json格式的数据title: '通知公告',iconCls: 'icon-view',height: 650,width: function () { return document.body.clientWidth * 0.9 },//自动宽度nowrap: true,autoRowHeight: true,striped: true,collapsible: true,pagination: true,pageSize: 50,pageList: [50, 100, 200],rownumbers: true,//sortName: 'ID',    //根据某个字段给easyUI排序sortOrder: 'asc',remoteSort: false,idField: 'ID',queryParams: queryData,  //异步查询的参数columns: [[{ field: 'ck', checkbox: true },   //选择{ title: '标题', field: 'Title', width: 350, sortable: true },{ title: '编辑者', field: 'Editor', width: 80, sortable: true },{ title: '编辑时间', field: 'EditTime', width: 150, sortable: true },{ title: '附件', field: 'Attachment_GUID', width: 250, sortable: true }]],toolbar: "#gridtoolbar",

然后在HTML里面添加gridtoolbar的层定义,作为easyUI的表格控件的工具条。由于使用了HTML辅助类来实现界面控件代码控制生成,因此已经可以达到了界面权限的控制了。使用这种HTML层定义的工具条定义方式,比通过脚本定义的工具条效果少了一个分隔线,其他的都还是一致的。

    <div id="gridtoolbar" style="padding: 5px; height: auto"><div style="margin-bottom: 5px">@if (@ViewBag.AuthorizeKey.CanInsert){@Html.ActionLink("添加", null, null, new {οnclick="ShowAddDialog()", data_options="iconCls:'icon-add', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"})}@if (@ViewBag.AuthorizeKey.CanUpdate){@Html.ActionLink("修改", null, null, new {οnclick="ShowEditOrViewDialog()", data_options="iconCls:'icon-edit', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"})}@if (@ViewBag.AuthorizeKey.CanDelete){@Html.ActionLink("删除", null, null, new {οnclick="Delete()", data_options="iconCls:'icon-remove', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"})}@if (@Html.HasFunction("Information/View")){@Html.ActionLink("查看", null, null, new {οnclick="ShowEditOrViewDialog('view')", data_options="iconCls:'icon-table', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"})}@Html.ActionLink("刷新", null, null, new {οnclick="$('#grid').datagrid('reload');", data_options="iconCls:'icon-reload', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"}) </div></div>

上面使用了两种方式来判断用户的权限的,一种是使用这种ViewBag对象的树形进行判断,如下所示。

@if (@ViewBag.AuthorizeKey.CanDelete)

还有一种是使用HTML辅助类的扩展方法进行判断,这种方法适用于一些非常规的权限控制集合的判断,如下所示

@if (@Html.HasFunction("Information/View"))

其中HTML辅助类方法是通过扩展静态方法进行实现,代码如下所示。

    public static class HtmlHelpers{public static bool HasFunction(this HtmlHelper helper, string functionId){return Permission.HasFunction(functionId);}public static bool IsAdmin(){return Permission.IsAdmin();}}

上面的界面控制方法,是通过控制界面代码的生成与否进行权限控制的,前面我们讲了,通过后台代码的控制器方法也是可以实现控制,而且是抛出自定义的错误,那么我们在使用Ajax方法调用的时候,也可以对这个错误信息进行友好显示,提示用户权限不足,前端页面操作代码如下。

        //绑定添加按钮的事件function BindAddEvent() {$("#btnAddOK").click(function () {//判断表单的信息是否通过验证var validate = $("#ffAdd").form('validate');if (validate == false) {return false;}var postData = $("#ffAdd").serializeArray();$.post("/Information/Insert", postData, function (data) {if (data = "true") {//添加成功  1.关闭弹出层,2.刷新DataGird$.messager.alert("提示", "添加成功");$("#DivAdd").dialog("close");$("#grid").datagrid("reload");$("#ffAdd").form("clear");//本页面的类型为【通知公告】,固定不变$("#Category").val("通知公告");}else {$.messager.alert("提示", "添加失败,请您检查");}}).error(function () {$.messager.alert("提示", "您未被授权使用该功能,请联系管理员进行处理。", 'warning');});});}

以上就是我对Web开发框架中的权限控制几个方面的思路和代码,希望抛砖引玉,获得大家更好的反馈和支持。

转载于:https://www.cnblogs.com/telwanggs/p/7125369.html

(转)基于MVC4+EasyUI的Web开发框架形成之旅--权限控制相关推荐

  1. (转)基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

    http://www.cnblogs.com/wuhuacong/p/3284628.html 自从上篇<基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍>总体性的概括,得到 ...

  2. (转)基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍

    http://www.cnblogs.com/wuhuacong/p/3344096.html 在前面介绍了一些关于最新基于MVC4+EasyUI的Web开发框架文章,虽然Web开发框架的相关技术文章 ...

  3. (转)基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用

    http://www.cnblogs.com/wuhuacong/p/3317223.html 在前面介绍了两篇关于我的基于MVC4+EasyUI技术的Web开发框架的随笔,本篇继续介绍其中界面部分的 ...

  4. (转)基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍

    http://www.cnblogs.com/wuhuacong/p/3281103.html 最近花了很多时间在重构和进一步提炼Winform开发框架的工作上,加上时不时有一些项目的开发工作,我博客 ...

  5. (转)基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用

    http://www.cnblogs.com/wuhuacong/p/3343967.html 大概一年前,我还在用Asp.NET开发一些行业管理系统的时候,就曾经使用这个组件作为文件的上传操作,在随 ...

  6. (转)基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

    http://www.cnblogs.com/wuhuacong/p/3352016.html 在上一篇随笔中,我对Web开发框架的总体界面进行了介绍,其中并提到了我的<Web开发框架>的 ...

  7. 基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览

    在博客园很多文章里面,曾经有一些介绍Office文档预览查看操作的,有些通过转为PDF进行查看,有些通过把它转换为Flash进行查看,但是过程都是曲线救国,真正能够简洁方便的实现Office文档的预览 ...

  8. 基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

    在很多Web界面中,我们都可以看到很多下拉列表的元素,有些是固定的,有些是动态的:有些是字典内容,有些是其他表里面的名称字段:有时候引用的是外键ID,有时候引用的是名称文本内容:正确快速使用下拉列表的 ...

  9. 基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码

    基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码 在Web开发的时候,我们很多时候,需要引用很多CSS文件.JS文件,随着使用更多的插件或者独立样式文件 ...

最新文章

  1. 用数据分析蔡徐坤1亿转发量幕后推手被封后能否动摇饭圈文化?
  2. Mvc多级Views目录 asp.net mvc4 路由重写及 修改view 的寻找视图的规则
  3. 什么是加密?—Vecloud微云
  4. springboot教程-web(二)
  5. 计算机net use命令使用,网络命令net之net use应用
  6. kafka分区机制详解
  7. MySql 1248 - Every derived table must have its own alias
  8. 窝囊同事做测试三年未涨工资,被开当天,bat全部大佬门口迎接!
  9. 计算机网络 --- HTTP协议 和 HTTPS
  10. 网络抖动多少ms算正常_如何测试延时、抖动、丢包率
  11. 聊天别被人家说的“职业技术”忽悠了
  12. 如何知道 win10 的激活到期时间和期限等
  13. PADS导入【ORCAD原理图文件】【导入ORCAD16.3原理图】 【layout如何进行“ECO对比更新”】【打开文件出错:*因为当前设计处于默认层模式下........】
  14. 计算机的英文原词“computer”
  15. 好用的可视化报表在线生成工具
  16. 2018保研夏令营调研笔记
  17. java socket通信 客户端_JavaのSocket编程之简单客户端与服务器端通信
  18. 入坑QT3之安装之后的系统环境配置和程序打包过程------主要是程序打包之后出现各种文件缺失问题
  19. qq炫舞摘经验秒级计算机,QQ炫舞8周年回归秒升30级活动
  20. IOS开发系列之阿堂教程:构建开发IOS应用的虚拟机开发环境实践

热门文章

  1. NameNode之文件系统目录树
  2. Apache 虚拟主机
  3. (14)Vivado开发流程(FPGA不积跬步101)
  4. (21)FPGA面试技能提升篇(JESD204B接口)
  5. JAVA输出两个顺序链表的并集_(顺序表)两个集合求并集-洋葱先生-杨少通
  6. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之第一个驱动
  7. STC51-键盘检测
  8. Linux 内核的同步机制,第 1 部分(来自IBM)
  9. 内核并发控制---读写信号量(来自网易)
  10. linux 安装vsftpd服务器,linux安装vsftpd和vsftpd配置步骤