背景:
最近看到不少关于权限设计的文章,发现很多都只是谈了个大概的设计方案,实现部分代码非常少。正好前段时间也弄了套自己的方案,俺跟着也凑凑热闹。
系统分析:
权限:
在系统中,权限通过模块+动作来产生,模块就是整个系统中的一个子模块,可能对应一个菜单,动作也就是整个模块中(在B/S 系统中也就是一个页面的所有操作,比如“浏览、添加、修改、删除”等)。将模块与之组合可以产生此模块下的所有权限。
角色:
权限的集合,角色与角色之间属于平级关系,将基本权限添加到一个角色中,方便权限的分配。
表设计:
我这里偷了个懒,将角色表、角色_权限表二表合一。
角色表:Role: iSyscode,cName,cMenuList,dDate,iStatusCode
权限表:Menu:iSysCode,cName,iParentID,dDate,iStatusCode
过程:
1、登录:
用户登录提取其角色ID,根据角色ID取出其享有的权限cMenuList。后台操作树根据这个权限集合动态生成。需要说明的是这棵树无刷新动态提取子项。
效果:
2 1 public void Treeview1_TreeNodePopulate( object sender, TreeNodeEventArgs e)
3 2 {
4 3 if (IsCallback)
5 4 {
6 5 if (e.Node.ChildNodes.Count == 0)
7 6 {
8 7 LoadChildNode(e.Node);
9 8 }
10 9 }
1110 }
12 11
13 12 private void LoadChildNode(TreeNode node)
14 13 {
1514 int iParentID = Convert.ToInt32(node.Value);
1615 //1 系统管理员 //2 总经理 //3 用户
1716 Basic_Menu bmMain = new Basic_Menu();
1817 IList<Basic_MenuInfo> bmInfoList = bmMain.GetMenu_List(1, iParentID);
1918
2019 foreach (Basic_MenuInfo bmInfo in bmInfoList)
2120 {
2221 TreeNode subNode = new TreeNode(bmInfo.cName);
2322 subNode.Value = bmInfo.iSysCode.ToString();
2423 subNode.NavigateUrl = "http://www.lxqq.cn";
2524 subNode.Target = "_blank";
2625
2726 try
2827 {
2928 if (bmInfo.iChildCount > 0)
3029 {
3130 subNode.SelectAction = TreeNodeSelectAction.SelectExpand;
3231 subNode.PopulateOnDemand = true;
3332 subNode.NavigateUrl = "#";
3433 }
3534 }
3635 catch
3736 {
3837 subNode.ImageUrl = "WebResource.axd?a=s&r=TreeView_XP_Explorer_ParentNode.gif&t=632242003305625000";
3938 }
4039 node.ChildNodes.Add(subNode);
4140 }
4241
4342 }
2、权限设置:
在这里我用Div布局,用Css设定缩进效果,后台用了个递归取出所有权限项,并根据所设置对象拥有的权限项设定checkbox的状态是否选中。设置完毕,(用hidden包存所有选中项),后台用Request.Form取出所有选定项的值加以操作。在这还有一个重点是checkbox的onclick操作。如选中父项,则相应子项也随之选中;子项选中,父项也跟着选中。在这里,要感谢我的老大。呵呵,因为我刚弄到这,就发现我老大有这个功能的JS实现。稍加改动,呵呵,正好用到这里。
代码:
2 1 protected void Page_Load( object sender, EventArgs e)
3 2 {
4 3 if (!this.IsPostBack)
5 4 {
6 5 string str = BasicMenuList(0);
7 6 content.InnerHtml = str;
8 7
9 8 string strMenuItem="1,2,3,4,5,6,7,8,11";
10 9 WebUtility.ScriptStartupRegister(this.Page, "SetDefaultValue('"+strMenuItem+"')");
1110 }
1211 }
13 12 private string BasicMenuList( int iParentID)
14 13 {
1514 string result = "";
1615 //1 系统管理员 //2 总经理 //3 用户
1716 Basic_Menu bmMain = new Basic_Menu();
1817 IList<Basic_MenuInfo> bmInfoList = bmMain.GetMenu_List(1, iParentID);
1918
2019 foreach(Basic_MenuInfo bmInfo in bmInfoList)
2120 {
2221 result += "<div class=\"divIndent2\">" + string.Format("<input type=\"checkbox\" id=\"cb{0}\" parentID=\"{3}\" childCount=\"{4}\" value=\"{1}\" οnclick=\"DoSelect(this);\">{2}", bmInfo.iSysCode, bmInfo.iSysCode, bmInfo.cName, iParentID, bmInfo.iChildCount);
2322 if (bmInfo.iChildCount > 0)
2423 {
2524 result += BasicMenuList(bmInfo.iSysCode);
2625 }
2726
2827 result += "</div>";
2928 }
3029 return result;
3130 }
JS实现代码:
2 1 < div style = " text-align: left; " >
3 2 < div > 权限管理示例 < / div><br / >
4 3 < div id = " content " class = " divIndent1 " runat = " server " >
5 4 < / div>
6 5 < br / >
7 6 < asp:Button ID = " btnShow " Text = " SET-Permission " OnClientClick = " return setValue(); " runat = " server " OnClick = " btnShow_Click " / >
8 7 < input type = " hidden " id = " hiddenRes " runat = " server " / >
9 8 < / div>
10 9
11 10 < script language = " javascript " type = " text/javascript " >
12 11 var checkStatus;
13 12
14 13 // 将值保存在Hidden里,以便后台读取
15 14 function setValue()
16 15 {
17 16 var t = document.getElementsByTagName("input");
18 17 var str="";
19 18
20 19 for(var i=0; i<t.length; i++)
21 20 {
22 21 if (t[i].type == "checkbox" && t[i].checked==true)
23 22 {
24 23 str+=t[i].value+",";
25 24 }
26 25 }
27 26 document.getElementById("hiddenRes").value=str;
28 27 }
29 28
30 29 // 设置默认值
31 30 function SetDefaultValue( xValue )
32 31 {
33 32 var x;
34 33 if( xValue.length == 0)
35 34 {
36 35 return false;
37 36 }
38 37 else
39 38 {
40 39 x = xValue.split(",");
41 40 }
42 41
43 42 with( document.all)
44 43 {
45 44 for( var i = 0; i<x.length; i++)
46 45 {
47 46 item("cb" + x[i]).checked = true;
48 47 }
49 48 }
50 49 }
51 50
52 51 //
53 52 function DoSelect(objElement)
54 53 {
55 54 var iParentID=objElement.parentID;
56 55 var iSysCode=objElement.value;
57 56 checkStatus = objElement.checked;
58 57
59 58 //处理自己
60 59 //if()
61 60 //处理父节点
62 61 if(checkStatus==true)//选中则处理父节点
63 62 {
64 63 DoSelectParent(iParentID);
65 64 DoSelectChild(iSysCode);
66 65 }
67 66 //处理子节点
68 67 if(checkStatus==false)
69 68 {
70 69 DoSelectChild(iSysCode);
71 70 }
72 71 }
73 72
74 73 // 处理父节点
75 74 function DoSelectParent(iParentID)
76 75 {
77 76 var t = document.getElementsByTagName("input");
78 77
79 78 for(var i=0; i<t.length; i++)
80 79 {
81 80 if (t[i].type == "checkbox" && t[i].value==String(iParentID))
82 81 {
83 82 t[i].checked = checkStatus;
84 83 if( t[i].parentID != 0)
85 84 {
86 85 DoSelectParent(t[i].parentID);
87 86 }
88 87 }
89 88 }
90 89 }
91 90
92 91 // 处理子节点
93 92 function DoSelectChild(iSysCode)
94 93 {
95 94 var t = document.getElementsByTagName("input");
96 95
97 96 for(var i=0; i<t.length; i++)
98 97 {
99 98 if (t[i].type == "checkbox" && t[i].parentID==String(iSysCode))
100 99 {
101100 t[i].checked = checkStatus;
102101 if( t[i].childCount!=0)
103102 {
104103 DoSelectChild(t[i].value);
105104 }
106105 }
107106 }
108107 }
109 108 < / script>
以前还从没想过可以在HTML元素里自定义属性,这里我在checkbox里添加了好几个,parentID,childCount.别说,还真好用。
说明:
此权限设计实为测试版本,实际开发中,数据库设计将进一步分解。例如分为:用户表Users,权限表:Permission 角色表Role,用户角色表:User_Role,角色权限表:Role_Permission。另外如果有需要的话,还可以进一步分为栏目权限和操作权限,增加操作表:Operate 栏目操作表:Permission_Operate。
水平有限,写的有点乱。有什么不同意见欢迎一起交流!