前言

  • 这一篇我们将完成系统的权限设置功能以及不同角色用户登录系统后动态加载菜单。注意:此示例权限只针对菜单级,如果园友需要更复杂的系统权限设置,可以拓展到按钮级或属性级。
  • 用户的登录采用Form认证来实现,这样可以有效地防止非授权用户或页面链接对系统造成不安全的操作。

权限设置模块

  • 页面采用角色列表和菜单列表勾选的方式,即选择角色后勾选可以操作的菜单,这样具有才角色的用户就具有操作这些菜单的权限。界面设置如下:

  

  • 界面选择的roleID和menuID我们采用字符串的方式进行拼接。在controller中采用object类型进行接收,然后进行转化后就可以得到传入的值。权限设置的参考代码如下:
   public bool SetPermit(object RoleID, object MenuIDs)
{
try
{
string[] roleArr = RoleID as string[];
long roleID = Convert.ToInt64(roleArr[].ToString()); S_Role role = context.S_Roles.Where(x => x.ID.Equals(roleID)).FirstOrDefault(); //获取角色
role.S_Menus = new List<S_Menu>(); //删除先前设置的roleID的数据
List<S_Menu> listdate = context.S_Roles.Where(x => x.ID.Equals(roleID)).FirstOrDefault().S_Menus.ToList();
foreach (var item in listdate)
{
role.S_Menus.Remove(item);
} //写入现有的数据
string[] MenuArr = MenuIDs as string[];
string[] MenuArrString = MenuArr[].ToString().TrimEnd(',').Split(',').ToArray();
List<long> arr = new List<long>();
foreach (var item in MenuArrString)
{
arr.Add(Convert.ToInt64(item));
} //必须转化为list集合,否则会出现“已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭”错误
List<S_Menu> query = (from m in context.S_Menus where arr.Contains(m.ID) select m).ToList(); foreach (S_Menu menu in query)
{
role.S_Menus.Add(menu);
menu.S_Roles = new List<S_Role>();
menu.S_Roles.Add(role);
} //EF默认启用了事务提交
context.SaveChanges();
return true;
}
catch
{
return false;
}
}
  • 由于想要在权限设置成功后能够反映角色拥有操作哪些菜单的权限,因此,我们需要对角色的easyui-datagrid追加点击事件,并且异步加载具有的菜单权限。Easyui-Datagrid本身具有一个很有用的数据方法unselectAll(取消选中当前页所有的行)。但需要放置在选中的菜单权限之前。参考代码如下:
$('#dg').datagrid({
onClickRow: function (index, data) {
var row = $('#dg').datagrid('getSelected');
if (row) {
var RoleID = row.ID;
$.ajax({
url: '/System/GetPermit',
type: 'POST',
data: { RoleID: RoleID },
success: function (data) {
$('#dgMenu').treegrid('unselectAll'); //重新加载 $('#dgMenu').treegrid({
onLoadSuccess: function (dataaa) {
$.each(data, function (index, item) {
$('#dgMenu').treegrid('selectRow', item); //选中设置的权限
});
}});
}
})}} });

系统登录用户获取菜单操作权限

  • 在我们把权限设置模块完成后就可以使不同角色的用户登录系统后操作不同的菜单权限。由于菜单采用的是easyui-tree来绑定的数据,所以我们需要定义一个符合easyui-tree属性的数据模型,这样就可以序列化easyui-tree识别的json数据格式呢。(这和之前的easyui-treegrid使用方式是一样的)。参考代码如下:
  public class mod_S_RoleMenuTree
{
public long id { get; set; } // 节点的ID
public string text { get; set; } //节点显示的文字
public string iconCls { get; set; }
public string url { get; set; }
public int treelevel { get; set; }
//节点状态,有两个值 'open' or 'closed', 默认为'open'. 当为‘closed’时说明此节点下有子节点否则此节点为叶子节点
public string state { get; set; }
public List<mod_S_RoleMenuTree> children { get; set; }// 子节点集合
}
  • 在MainController中我们可以根据登录的用户名获取该用户角色所具有的菜单权限。由于此示例的菜单只设置了两级,所以没有做递归。如果需要多级菜单,可以参照上一篇文章将以下方法修改成递归方法,参考代码如下:
  public ActionResult GetRoleMenus()
{
string strUser = System.Web.HttpContext.Current.User.Identity.Name;
List<S_Menu> listData = IS_Role.GetRoleMenus(strUser); var listDataParent = listData.Where(x => x.PID.Equals(null)).OrderBy(x => x.SerialNO); List<mod_S_RoleMenuTree> DataModel = new List<mod_S_RoleMenuTree>(); foreach (var item in listDataParent)
{
mod_S_RoleMenuTree model = new mod_S_RoleMenuTree();
model.id = item.ID;
model.text = item.MenuName;
model.iconCls = item.Icon;
model.state = "open";
model.url = item.Link;
model.treelevel = item.Level;
model.children = new List<mod_S_RoleMenuTree>(); var children = listData.Where(x => x.PID.Equals(item.ID)).OrderBy(x => x.SerialNO);
foreach (var childitem in children)
{
mod_S_RoleMenuTree childmodel = new mod_S_RoleMenuTree();
childmodel.id = childitem.ID;
childmodel.text = childitem.MenuName;
childmodel.iconCls = childitem.Icon;
childmodel.state = "open";
childmodel.url = childitem.Link;
model.treelevel = childitem.Level;
model.children.Add(childmodel);
} DataModel.Add(model);
} return Json(DataModel, JsonRequestBehavior.AllowGet);
}
  • 再将MainController中的Index视图中的获取菜单数据的代码替换成以下代码,这样我们可以动态从数据库中读取菜单,而不是直接读取json文件。
   <ul class="easyui-tree" id="txt"
data-options="url:'/Main/GetRoleMenus',method:'get',animate:true,lines:true"></ul>

登录功能

  • 我们为系统设置了连个账户admin\Jack,admin具有管理员角色,Jack具有操作员角色,因此两个用户登录后看到的菜单是不一样的。用户登录参考代码如下:
  [HttpPost]
  public ActionResult Login(mod_Account model)
{
if (null != model){
if (IS_User.Login(model.UserName, DESEncrypt.Encrypt(model.UserPwd))){
System.Web.Security.FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("Index", "Main");
}
else{
return View();
}
}
else{
return View();
}
}
  • 由于采用Form认证,所以我们还需要在配置文件中修改一下代码:
  <authentication mode="Forms">
<forms loginUrl="/Account/Login" timeout="" protection="All" />
</authentication>
<authorization>
<deny users="?"/>
</authorization>
  • 退出时,需要注销认证用户,参考代码如下: 
  public ActionResult LoginOut()
{
System.Web.Security.FormsAuthentication.SignOut();
return RedirectToAction("Login", "Account");
}
  • 到此,我们完成了此示例的基本功能模块,本示例源码已放置网盘,点此下载。不同用户登录系统显示的页面结果如下:

  

  

  

EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(九)的更多相关文章

  1. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(一)

    前言 本系列源自对EF6 CodeFirst的探索,但后来发现在自己项目中构建的时候遇到了一些问题以及一些解决方法,因此想作为一个系列写下来. 本系列并不是教你怎么做架构设计,但可以参照一下里面的方法 ...

  2. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(六)

    前言 在接下来的篇幅里将对系统的模块功能进行编写.主要以代码实现为主.这一篇我们需要完成系统模块“角色管理”的相关功能.完成后可以对系统框架结构有进一步了解. Abstract层 之前说过,Abstr ...

  3. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(完)

    前言 这一篇是本系列的最后一篇,虽然示例讲到这里就停止呢,但对于这些技术的学习远不能停止.虽然本示例讲的比较基础,但是正如我第一篇说到的,这个系列的目的不是说一些高端的架构设计,而是作为一个入门级,对 ...

  4. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(八)

    前言 本篇幅将对系统的菜单管理模块进行说明,系统的菜单采用树形结构,这样可以更好地方便层级设计和查看.本示例将说明如何通过EntityFramework读取递归的菜单树形结构,以及结合EasyUI的t ...

  5. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(七)

    前言 上一篇文章我们完成了系统角色管理的基本功能实现,也对系统层次结构进行了了解.这一篇我们将继续对系统的用户管理模块进行代码编写.代码没有做封装,所以大部分的逻辑代码都是相通的,只是在一些前端的细节 ...

  6. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(四)

    前言 这一篇,我们终于到了讲解Entity Framework CodeFirst 的时刻了,首先创建实体对象模型,然后会通过配置Fluent API的方式来对实体对象模型进行完整的数据库映射操作. ...

  7. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(三)

    前言 在上一篇中,我们依靠着EasyUI强大的前端布局特性把前端登录界面和主界面给搭建完成了.这一篇我们就要尝试着把整个解决方案部署到云端呢,也就是Visual Studio Online(TFVC) ...

  8. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(二)

    前言 写完第一篇后,我一直在想接下来应该从哪一方面开始讲.后来我觉得不用那么死板的把每一个课程和大纲都列出来吧,毕竟我又不是教书的,呵呵...我觉得就像做实验一样,我们一部分一部分的完成,最后总个结果 ...

  9. EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(五)

    前言 在编写代码的时候,我遇到了很多关于EntityFramework6的疑问,所以现在就提前把这些问题列出来做一下解答,以便在以后的代码编写过程中减少不必要的Bug. EntityFramework ...

随机推荐

  1. NOI 动态规划题集

    noi 1996 登山 noi 8780 拦截导弹 noi 4977 怪盗基德的滑翔翼 noi 6045 开餐馆 noi 2718 移动路线 noi 2728 摘花生 noi 2985 数字组合 no ...

  2. laravel框架总结(十三) -- redis使用

    一切的前提都是已经安装好了redis服务器,并且能启动(我只总结了mac的安装方法:传送门) 我自己使用的是mac系统,有个教程可以参考下,传送门: 1.安装PHP PRedis 1>PRedi ...

  3. HQL查询——关联和连接

    HQL查询--关联和连接 为了便于理解有关的使用关联和连接进行HQL查询,首先提供两个具有关联关系的持久化类:Person类和MyEvent类 Person类: import javax.persis ...

  4. Spring+quartz整合问题

    今天一开始在弄quartz的时候用的2.0.2的jar包整合Spring3.0.5的时候报错 Java.lang.IncompatibleClassChangeError: class org.spr ...

  5. python之路3:

    class set(object): """ set() -> new empty set object set(iterable) -> new set o ...

  6. crontab Job权限重要

    在撰写JOb时,需要将SH目录及文件设为777,方可正常执行~

  7. T-SQL编程 —— 用户自定义函数(标量函数)

    用户自定义函数 在使用SQL server的时候,除了其内置的函数之外,还允许用户根据需要自己定义函数.根据用户定义函数返回值的类型,可以将用户定义的函数分为三个类别: 返回值为可更新表的函数 如果用 ...

  8. C#返回时间格式转换成 js 字符串

    在.net 中,调用 post 或者 get和后台通信时,如果有时间返回信息,后台返回的时间信息一般是这样格式:Thu Jul 9 23:14:53 UTC+0800 2015,那么要在前台显示就会有 ...

  9. nginx 日志变量含义

    log_format logstash "remote_addr | $time_local | $request | $status | $body_bytes_sent | " ...

  10. php : 基础(4)

    流程控制 循环结构 循环的中断 循环中,有两种中断语句可以使用: break: 用于完全终止某个循环,让执行流程进入到循环语句后面的语句: continue: 用于停止当前正在进行的当次循环,而进入到 ...