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,Code
var 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> : BaseController
where B : class
where 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是grid
url: '/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 {onclick="ShowAddDialog()", data_options="iconCls:'icon-add', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"})
}
@if (@ViewBag.AuthorizeKey.CanUpdate)
{
@Html.ActionLink("修改", null, null, new {onclick="ShowEditOrViewDialog()", data_options="iconCls:'icon-edit', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"})
}
@if (@ViewBag.AuthorizeKey.CanDelete)
{
@Html.ActionLink("删除", null, null, new {onclick="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 {onclick="ShowEditOrViewDialog('view')", data_options="iconCls:'icon-table', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"})
}
@Html.ActionLink("刷新", null, null, new {onclick="$('#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开发框架中的权限控制几个方面的思路和代码,希望抛砖引玉,获得大家更好的反馈和支持。

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

  1. 基于MVC4+EasyUI的Web开发框架形成之旅--权限控制

    我在上一篇随笔<基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍>中大概介绍了基于MVC的Web开发框架的权限控制总体思路.其中的权限控制就是分为“用户登录身份验证” ...

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

    大概一年前,我还在用Asp.NET开发一些行业管理系统的时候,就曾经使用这个组件作为文件的上传操作,在随笔<Web开发中的文件上传组件uploadify的使用>中可以看到,Asp.NET中 ...

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

    最近花了很多时间在重构和进一步提炼Winform开发框架的工作上,加上时不时有一些项目的开发工作,我博客里面介绍Web开发框架的文章比较少,其实以前在单位工作,80%的时间是做Web开发的,很早就形成 ...

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

    自从上篇<基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍>总体性的概括,得到很多同行的关注和支持,不过上一篇主要是介绍一个总体的界面效果和思路,本系列的文章将逐步介绍其中的 ...

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

    在前面介绍了两篇关于我的基于MVC4+EasyUI技术的Web开发框架的随笔,本篇继续介绍其中界面部分的一些使用知识,包括控件的赋值.取值.清空,以及相关的使用. 我们知道,一般Web界面包括的界面控 ...

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

    在前面介绍了一些关于最新基于MVC4+EasyUI的Web开发框架文章,虽然Web开发框架的相关技术文章会随着技术的探讨一直写下去,不过这个系列的文章,到这里做一个总结,展示一下整体基于MVC4+Ea ...

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

    在上一篇随笔中,我对Web开发框架的总体界面进行了介绍,其中并提到了我的<Web开发框架>的控制器的设计关系,Web开发框架沿用了我的<Winform开发框架>的很多架构设计思 ...

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

    原文  http://www.cnblogs.com/wuhuacong/p/3317223.html 基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用 在前面介绍了两篇关于我的基 ...

  9. 基于MVC4+EasyUI的Web开发框架形成之旅(7)--权限控制

    我在上一篇随笔<基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍>中大概介绍了基于MVC的Web开发框架的权限控制总体思路.其中的权限控制就是分为“用户登录身份验证” ...

随机推荐

  1. 08.Web服务器-4.Web服务器动态资源请求

    1 浏览器请求动态页面过程 2 WSGI 怎么在你刚建立的Web服务器上运行一个Django应用和Flask应用,如何不做任何改变而适应不同的web架构呢? 在以前,选择 Python web 架构会 ...

  2. Vue CLI 3.x 简单体验

    文档 中文文档 补充于02月10日 vue脚手架的3.x版本已经在开发中,现在还处于alpha版本.我们来看看有哪些变化. 使用 npm install -g @vue/cli 命名方式已经改为npm ...

  3. WPF通过鼠标滑轮缩放显示图片

    如果你使用WinForm比较难实现通过滚动鼠标滑轮来对图片进行缩放显示,那么,你应该考虑一下使用WPF,既然是下一代Windows客户端开发平台,明显是有一定优势的,不然,MS是吃饱了撑着.   首先 ...

  4. 重新学习html和css

    当初学习前端的时候,属于快速入门那种,没有好好深入学习html和css.如今,在空闲时间重新拿起基础书学习,都会写到一些新的知识. 1.css实现圆角.渐变功能.使用border-radius以及li ...

  5. 去除html标签 php

    function my_html($string,$sublen =80){ $string = strip_tags($string); $string = preg_replace ('/\n/i ...

  6. Navicat Premium (patch and keygen)

    标签:Navicat 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://sofar.blog.51cto.com/353572/13 ...

  7. SpringBoot支持AJAX跨域请求

    利用注解的方式解决AJAX请求跨域问题 1.编写一个支持跨域请求的 Configuration - 第一种方式 - CorsConfig.java import org.springframework ...

  8. int*与(int*)的差别

    晚上被问到一个C++的问题: int **pa=new int* [5]; int *pb=new (int*)[5]; 上面两行代码的差别是什么? 分析与实验结果例如以下: (1)第一行代码能够在V ...

  9. kvc和kvo的使用情况的了解

    了解cocoa:Cocoa是苹果公司为Mac OS X所创建的原生面向对象的API,是Mac OS X上五大API之中的一个(其他四个是Carbon.POSIX.X11和Java). 苹果的面向对象开 ...

  10. Linux下把目录拷贝到全部同名目录的脚本

    需求:拷贝文件夹到Linux文件夹下.覆盖该Linux文件夹下全部同名文件夹 目标:Linux下,运行本脚本.输入目录名.就可以批量复制覆盖. 使用说明:         先把本脚本文件和要复制的文件 ...