在asp.net后台管理系统开发中,有一个永远绕不过去的核心功能,那就是权限管理。他使你的整个管理系统活了过来,可以适应公司不同职位人员的使用。
下边是我搭得简易界面效果图:
1、基本需求
看界面你就知道,你首先最少应该有三个模块显示,包括你的模块管理、角色管理、管理员的人员管理。
在数据库中你最少需要四个表,其他的看个人需要了。这四个表分别是
Module(模块表)、User(管理员表)、Role(角色表)、Role_Module(角色_模块授权记录表)。
2、界面生成
因为我使用的是EF,所以实体类生成就直接跳过了。
页面搭建和基本的页面显示使用的是Ajax+easyUI,这个也随自己的写法写,毕竟每个人的设计都不一样。
3、登录界面
做权限你肯定需要一个登录页面,登录页面找模板还是自己设计需要你自己找了,我主要是说一下后台的代码,进行功能的实现。
首先在登录的数据访问层(LoginDal)中添加对数据的操作
public IEnumerable<Module> GetMenu(int rid)
{
return Ef.Role_Module.Where(x => x.Role.ID == rid
&&x.Module.M_type=="1" &&
x.Module.M_ParentID==0).ToList().Select(x => new Module {
M_name = x.Module.M_name,M_path = x.Module.M_path,
M_IconCls = x.Module.M_IconCls,ID=x.Module.ID }).ToList();
}
注:(1)IEnumerable<>是一个数据的结构,指可用foreach遍历的“集合”。
他会对你理解IEnumerable<>有一些帮助
(2)方法是通过不同角色、是否是为“1”一级菜单,是否是为0的菜单,不是按钮。来查出一级菜单,然后查询一个NEW Module数据。
然后是在业务逻辑层(LoginBll)中进行业务操作:
public IEnumerable<Module> GetMenu(int rid)
{
LoginDal realDal = (LoginDal)Dal;
return realDal.GetMenu(rid);
}
继承Dal中的方法。
public User GetUserByNamePaw(LoginModel model)
{
Expression<Func<User, bool>> where = x => x.U_name == model.name && x.U_pwd == model.pwd;
return Dal.Search(where).FirstOrDefault();
}
LoginModel是我自定义的一个实体类,其中存放了定义的密码,账号和可能用到的验证码。
Expression<Func<User, bool>
根据条件动态生成LINQ查询条件,将Func类型的变量作为参数传给Where方法。
在EF中,如果单一将Func类型的变量作为参数传给Where方法进行LINQ查询,会造成全表查询的错误,将整个数据库表中的数据加载到内存
[Required]
public string name { get; set; }
[Required]
public string pwd { get; set; }
[Required]
public string code { get; set; }
方法使model类中的元素和数据库中的元素对应。然后返回Dal中的查询方法。
最后在Login的控制器中实现对账号密码的操作。
public ActionResult Login(string name, string pwd)
{
var loginUser = Bll.Search(x => x.U_name == name && x.U_pwd == pwd).FirstOrDefault();
if (loginUser != null)
{
Session["LoginUser"] = loginUser;
string mag = "登录成功";
var user = Session["LoginUser"];
return Json(new { state = true, mag = mag},JsonRequestBehavior.AllowGet);
}
else
{
string mag = "登录失败";
return Json(new { state = false, mag = mag }, JsonRequestBehavior.AllowGet);
}
}
获取密码,判断密码是不是非空,只有一个判断,比较简单。
在前台加入常用的JavaScript前台验证
function submit1() {
if ($("#Username").val() == "" || $("#Password").val() == "")
{
return;
}
$.ajax({
url: '@Url.Action("Login")',
data: {
name:$("#Username").val(),
//serialize以键值对(Key/Value)的形式发送到服务器
dataType: "json",
type: "POST",
success: function (data) {
if (data.state == true) {
window.location = '@Url.Action("Index","Home")';
}
else {
alert("账号或者密码错误");
$("#password").focus();
}
},
error: function () {
alert("登录出现问题,请联系系统管理员");
}
})
}
4、角色的权限分配
角色权限设置在角色管理中实现,但是他获取的信息是模块表信息,设置成功过的信息保存在连接表中。
(1)权限树
所以先说在角色管理中的添加,主要是添加了一个权限管理的按钮,做了一个弹出表格,如下:
<a id="btn" class="easyui-linkbutton" iconcls="icon-more" onclick="setRole();">设置权限</a>
接下来是他的事件:
//设置权限
function setRole() {
var rows = $("#roleList").datagrid("getSelections");
if (rows.length!=1) {
$.messager.alert("提示", "请选中一行", "info");
return;
}
objModule.rid = rows[0].ID;
//objModule.rid为全局变量
$("#tree").tree({
url: "@Url.Action("GetModuleTree","Module")",
checkbox: true,
type: "post",
data: "",
dataType: "Json",
onLoadSuccess: function (data) {
selectNodes(objModule.rid);
}
});
$("#treedialog").dialog("open");
}
为了方便,他调用的后台方法写在了"GetModuleTree","Module"
的模块管理的控制器中,如下:
public ActionResult GetModuleTree()
{
return Json((Bll as ModuleBll).GetModuleTree(1));
}
他继承的bll方法方法为:
public List<ModuleTree> GetModuleTree(int id)
{
List<ModuleTree> mtl = new List<ModuleTree>();//声明一个list存数据
List<Module> m = Dal.Search(x => x.M_ParentID == 0).ToList();
foreach (var module in m)//将模型循环返回到树里边
{
ModuleTree mt = new ModuleTree();//声明一个模型树
mt.id = module.ID;
mt.text = module.M_name;
BindChild(mt);
mtl.Add(mt);
}
return mtl;
}
(2)角色设置判定
他作用主要也是生成一个 模型树。在他的JS代码中,点击响应成功后会触发selectNodes事件,如下:
function selectNodes(id) {
$.ajax({
url: "@Url.Action("GetModulesByRole","Module")?rid=" + id,
dataType: "Json",
type: "post",
success: function (data) {
for (var i = 0; i < data.length; i++) {
var node = $("#tree").tree("find", data[i].toString());//找到指定的节点
if (node != null) {
if (node.children.length == 0) {
$("#tree").tree("check", node.target);//选中该节点
}
}
}
}
});
}
他调用的方法为:
public ActionResult GetModulesByRole(string rid)
{
int rId = 0;
if (rid != null)
{
rId = int.Parse(rid);
}
return Json((Bll as ModuleBll).GetModulesByRoleID(rId));
}
他主要是通过判断角色ID来给予权限,他继承的BLL为:
public IEnumerable<int> GetModulesByRoleID(int rid)
//通过角色ID获取模块列表
{
Role_ModuleBll powerBll = new Role_ModuleBll();
return powerBll.Search(x => x.Role.ID == rid).ToList().Select(x => x.Module.ID).ToList();
}
(3)保存权限
<div id="btnstree">
<a class="easyui-linkbutton" iconcls="icon-redo" onclick="closeDialog();">取消</a>
<a class="easyui-linkbutton" iconcls="icon-ok" onclick="saveRole();">保存</a>
</div>
接下来是保存事件,当然记得把你的表格在初始化时进行设置。
function saveRole() {
getCheckedNodes();
};
响应的另外一个判断是否成功的事件。
function getCheckedNodes() {
var rId = objModule.rid;
var nodes = $("#tree").tree("getChecked");
var parentNodes = $("#tree").tree("getChecked", "indeterminate");
var nodesArray = [];
var strNodes = "";
for (var i = 0; i < nodes.length; i++) {
nodesArray.push(nodes[i].id);
}
for (var i = 0; i < parentNodes.length; i++) {
nodesArray.push(parentNodes[i].id);
}
strNodes = nodesArray.join(',');
$.ajax({
url: "@Url.Action("SaveMoundle", "Module")",
dataType: "Json",
type:"post",
data: { rId: rId, nodes: strNodes },
success: function (data) {
if (data == "ok") {
alert('设置成功');
}
else {
alert("设置失败");
}
$("#roleList").datagrid("load", {
M_ParentID: 0,
});
$("#Tree").tree("reload");
closeDialog();
}
});
}
他的作用主要体现在表单上和模块树上,他调用了方法为:
public ActionResult SaveMoundle(int rId, string nodes)
{
Role_ModuleBll urbll = new Role_ModuleBll();
bool a = false;
string[] strArrayIds = nodes.Split(',');//根据逗号分隔
urbll.DeleteNoSave(x => x.R_ID == rId);
if (strArrayIds.Length > 0 && strArrayIds[0] != "")
{
int[] intArrayIds = Array.ConvertAll<string, int>(strArrayIds, x => Convert.ToInt32(x));
foreach (var item in intArrayIds)
{
Role_Module us = new Role_Module();
us.R_ID = rId;
us.M_ID = item;
urbll.AddNoSave(us);
}
}
a = urbll.Save() > 0;
if (a)
{
return Json("成功");
}
else
{
return Json("失败");
}
}
进行添加判断,如果成功保存到Role_Module中,失败则返回失败信息。
基本上功能就是这样,其中模块表的设置可能会麻烦一点,可以按照自己的需求做一下。
如果出现了明显错误请记得说明或者补充留言,谢谢。