背景:
最近看到不少关于权限设计的文章,发现很多都只是谈了个大概的设计方案,实现部分代码非常少。正好前段时间也弄了套自己的方案,俺跟着也凑凑热闹。
系统分析:
权限:
在系统中,权限通过模块+动作来产生,模块就是整个系统中的一个子模块,可能对应一个菜单,动作也就是整个模块中(在B/S 系统中也就是一个页面的所有操作,比如“浏览、添加、修改、删除”等)。将模块与之组合可以产生此模块下的所有权限。
角色:
权限的集合,角色与角色之间属于平级关系,将基本权限添加到一个角色中,方便权限的分配。
表设计:
我这里偷了个懒,将角色表、角色_权限表二表合一。
角色表:Role: iSyscode,cName,cMenuList,dDate,iStatusCode
权限表:Menu:iSysCode,cName,iParentID,dDate,iStatusCode
过程:
1、登录:
用户登录提取其角色ID,根据角色ID取出其享有的权限cMenuList。后台操作树根据这个权限集合动态生成。需要说明的是这棵树无刷新动态提取子项。
效果:
1
2
1public 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 }
11
10 }
12
11
13
12 private void LoadChildNode(TreeNode node)
14
13
{
15
14 int iParentID = Convert.ToInt32(node.Value);
16
15 //1 系统管理员 //2 总经理 //3 用户
17
16 Basic_Menu bmMain = new Basic_Menu();
18
17 IList<Basic_MenuInfo> bmInfoList = bmMain.GetMenu_List(1, iParentID);
19
18
20
19 foreach (Basic_MenuInfo bmInfo in bmInfoList)
21
20
{
22
21 TreeNode subNode = new TreeNode(bmInfo.cName);
23
22 subNode.Value = bmInfo.iSysCode.ToString();
24
23 subNode.NavigateUrl = "http://www.lxqq.cn";
25
24 subNode.Target = "_blank";
26
25
27
26 try
28
27
{
29
28 if (bmInfo.iChildCount > 0)
30
29
{
31
30 subNode.SelectAction = TreeNodeSelectAction.SelectExpand;
32
31 subNode.PopulateOnDemand = true;
33
32 subNode.NavigateUrl = "#";
34
33 }
35
34 }
36
35 catch
37
36
{
38
37 subNode.ImageUrl = "WebResource.axd?a=s&r=TreeView_XP_Explorer_ParentNode.gif&t=632242003305625000";
39
38 }
40
39 node.ChildNodes.Add(subNode);
41
40 }
42
41
43
42 }
2、权限设置:
在这里我用Div布局,用Css设定缩进效果,后台用了个递归取出所有权限项,并根据所设置对象拥有的权限项设定checkbox的状态是否选中。设置完毕,(用hidden包存所有选中项),后台用Request.Form取出所有选定项的值加以操作。在这还有一个重点是checkbox的onclick操作。如选中父项,则相应子项也随之选中;子项选中,父项也跟着选中。在这里,要感谢我的老大。呵呵,因为我刚弄到这,就发现我老大有这个功能的JS实现。稍加改动,呵呵,正好用到这里。

代码:
1
2
1protected 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+"')");
11
10 }
12
11 }
13
12 private string BasicMenuList(int iParentID)
14
13
{
15
14 string result = "";
16
15 //1 系统管理员 //2 总经理 //3 用户
17
16 Basic_Menu bmMain = new Basic_Menu();
18
17 IList<Basic_MenuInfo> bmInfoList = bmMain.GetMenu_List(1, iParentID);
19
18
20
19 foreach(Basic_MenuInfo bmInfo in bmInfoList)
21
20
{
22
21 result += "<div class=\"divIndent2\">" + string.Format("<input type=\"checkbox\" id=\"cb
{0}\" parentID=\"
{3}\" childCount=\"
{4}\" value=\"
{1}\" onclick=\"DoSelect(this);\">{2}", bmInfo.iSysCode, bmInfo.iSysCode, bmInfo.cName, iParentID, bmInfo.iChildCount);
23
22 if (bmInfo.iChildCount > 0)
24
23
{
25
24 result += BasicMenuList(bmInfo.iSysCode);
26
25 }
27
26
28
27 result += "</div>";
29
28 }
30
29 return result;
31
30 }
JS实现代码:
1
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
{
101
100 t[i].checked = checkStatus;
102
101 if( t[i].childCount!=0)
103
102
{
104
103 DoSelectChild(t[i].value);
105
104 }
106
105 }
107
106 }
108
107 }
109
108 </script>
以前还从没想过可以在HTML元素里自定义属性,这里我在checkbox里添加了好几个,parentID,childCount.别说,还真好用。
说明:
此权限设计实为测试版本,实际开发中,数据库设计将进一步分解。例如分为:用户表Users,权限表:Permission 角色表Role,用户角色表:User_Role,角色权限表:Role_Permission。另外如果有需要的话,还可以进一步分为栏目权限和操作权限,增加操作表:Operate 栏目操作表:Permission_Operate。
水平有限,写的有点乱。有什么不同意见欢迎一起交流!