最近看了许多权限管理的文章,把学习到的内容贴出来,希望大家能多多指教!
下边是一位前辈的理解,贴出来分享:
权限概念中,我认为原子元素只有三种:用户、功能权限、数据权限。其他的角色、用户组之类的东西都是为了解耦用户与其他元素之间关系而引入的,或者为了方便起见,都是一个中间变量而已。
1.功能权限。
针对某个一功能,是否能访问。比如此用户是否能访问读取客户资料的功能。这个权限比较基础,不是yes就是no,所以有人又称Y/N权限。
2.数据权限。
在允许访问某一功能权限的基础上,控制可访问的数据范围。比如用户能访问读取客户资料的功能,但他只能访问本人录入的,或分配给本部门的客户资料。
数据库设计:
用户表:设UserID、用户名、用户信息
角色表:设RoleID、CategoryID、RoleName、Description
用户角色表:UserID、RoleID
分类表:CategoryID、CategoryName、Description
许可表:PermissionID、CategoryID、PermissionName、Description
角色许可表:RoleID、PermissionID
设计好数据库后,即可以从事设计用户、角色、许可的类。类库分数据层类,完成建立、查询、删除、更新等操作。业务层的类,需要实现与数据无关功能,建立如用户拥有角色、许可的列表,验证方式等。
利用HttpContext类包含了个别HTTP请求的所有特定HTTP信息,可以使用HttpContext类中的User属性来实现用户验证
ASP.NET中内置的用户验证机制功能非常强大,同时也具有非常好的的可扩展性,它能够在HttpContext对象中生成一个名为User的属性,这个属性能让我们访问各种信息,包括用户是否已验证,用户的类型,用户名等等,我们还可以对该属性的功能进性扩展,以实现我们的要求。
分配给HttpContext.User的对象必须实现IPrincipal接口,而Iprincipal定义的属性之一是Identity,它必须实现Iidentity接口。因为,我们只要写了实现这两个接口的类,就可以在这些类中添加任何我们所需要的功能。
首先,我们创建两个实现Iprincipal和Iidentity的类,分另为MyIprincipal和MyIdentity


2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5
6 /// <summary>
7 ///MyIdentity 的摘要说明
8 /// </summary>
9 public class MyIdentity:System.Security.Principal.IIdentity
10 {
11 private string userID;
12 private string password;
13
14 public MyIdentity(string currentUserID,string currentPassword)
15 {
16 userID = currentUserID;
17 password = currentPassword;
18
19 }
20
21 /// <summary>
22 /// 检查用户是否存在
23 /// </summary>
24 private bool CanPass()
25 {
26 if (userID == "mofei" && password == "123")
27 {
28 return true;
29 }
30 return false;
31 }
32 public MyIdentity()
33 {
34 //
35 //TODO: 在此处添加构造函数逻辑
36 //
37 }
38
39 #region IIdentity 成员
40
41 public string AuthenticationType
42 {
43 get { return null; }
44 }
45
46 public bool IsAuthenticated
47 {
48 get { return CanPass(); }
49 }
50
51 public string Name
52 {
53 get { return userID; }
54 }
55
56 #endregion
57 }
58


2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Collections;
6
7 /// <summary>
8 ///MyPrincipal 的摘要说明
9 /// </summary>
10 public class MyPrincipal:System.Security.Principal.IPrincipal
11 {
12 private System.Security.Principal.IIdentity identity;
13 private ArrayList roleList;
14
15 public ArrayList RoleList
16 {
17 get { return roleList; }
18 }
19
20 public MyPrincipal(string userId,string password)
21 {
22 //
23 //TODO: 在此处添加构造函数逻辑
24 //
25 identity = new MyIdentity();
26 if (identity.IsAuthenticated)
27 {
28 //验证通过
29 //获取用户角色
30 roleList = new ArrayList();
31 roleList.Add("Admin");
32 }
33 else
34 {
35 //没有权限
36 }
37 }
38
39 #region IPrincipal 成员
40
41 public System.Security.Principal.IIdentity Identity
42 {
43 get { return this.identity; }
44 set { identity = value; }
45 }
46
47 public bool IsInRole(string role)
48 {
49 return roleList.Contains(role);
50 }
51
52 #endregion
53 }
54
在完成了这两个类之后我们还要创建一个自己的Page类,来配合我们的验证,这里我们将其命名为MyPage,继承自Page类


2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Collections;
6
7 /// <summary>
8 ///MyPage 的摘要说明
9 /// </summary>
10 public class MyPage:System.Web.UI.Page
11 {
12 public MyPage()
13 {
14 //
15 //TODO: 在此处添加构造函数逻辑
16 //
17 }
18 protected override void OnInit(EventArgs e)
19 {
20 base.OnInit(e);
21 this.Load+=new EventHandler(MyPage_Load);
22 }
23
24 private void MyPage_Load(object sender, System.EventArgs e)
25 {
26 if (Context.User.Identity.IsAuthenticated)
27 {
28 if (Context.Cache["UserMessage"] != null)
29 {
30 Hashtable userMessage=(Hashtable)Context.Cache["UserMessage"];
31 MyPrincipal principal = new MyPrincipal(userMessage["UserID"].ToString(),userMessage["UserPassword"].ToString());
32 Context.User = principal;
33 }
34 }
35 }
36 }
37
下面就是我们的界面WebForm.aspx和WebForm.aspx.cs


<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="HttpContextUserEG.WebForm1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="javascript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<P><FONT face="宋体">用户名:
<asp:TextBox id="tbxUserID" runat="server"></asp:TextBox><BR>
密 码:
<asp:TextBox id="tbxPassword" runat="server" TextMode="Password"></asp:TextBox></FONT></P>
<P><FONT face="宋体">
<asp:Button id="btnLogin" runat="server" Text="登录"></asp:Button>
<asp:Label id="lblLoginMessage" runat="server"></asp:Label></FONT></P>
<P><FONT face="宋体">
<asp:Panel id="Panel1" runat="server" Visible="False">
<P>
<asp:Button id="btnAdmin" runat="server" Text="角色1"></asp:Button>
<asp:Button id="btnUser" runat="server" Text="角色2"></asp:Button></P>
<P>
<asp:Label id="lblRoleMessage" runat="server"></asp:Label></P>
</asp:Panel>
<P></P>
</FONT>
</form>
</body>
</HTML>


2
3
4
5 using System;
6
7 using System.Collections;
8
9 using System.ComponentModel;
10
11 using System.Data;
12
13 using System.Drawing;
14
15 using System.Web;
16
17 using System.Web.Caching;
18
19 using System.Web.SessionState;
20
21 using System.Web.UI;
22
23 using System.Web.UI.WebControls;
24
25 using System.Web.UI.HtmlControls;
26
27
28
29 namespace HttpContextUserEG
30
31 {
32
33 /// <summary>
34
35 /// WebForm1 的摘要说明。
36
37 /// </summary>
38
39 /// 将这里本来继承自Page类改为继承自我们自己的MyPage类
40
41 public class WebForm1 : HttpContextUserEG.MyPage
42
43 {
44
45 protected System.Web.UI.WebControls.TextBox tbxUserID;
46
47 protected System.Web.UI.WebControls.TextBox tbxPassword;
48
49 protected System.Web.UI.WebControls.Panel Panel1;
50
51 protected System.Web.UI.WebControls.Button btnAdmin;
52
53 protected System.Web.UI.WebControls.Button btnUser;
54
55 protected System.Web.UI.WebControls.Label lblRoleMessage;
56
57 protected System.Web.UI.WebControls.Label lblLoginMessage;
58
59 protected System.Web.UI.WebControls.Button btnLogin;
60
61
62
63 private void Page_Load(object sender, System.EventArgs e)
64
65 {
66
67 // 在此处放置用户代码以初始化页面
68
69 }
70
71
72
73 #region Web 窗体设计器生成的代码
74
75 override protected void OnInit(EventArgs e)
76
77 {
78
79 //
80
81 // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
82
83 //
84
85 InitializeComponent();
86
87 base.OnInit(e);
88
89 }
90
91
92
93 /// <summary>
94
95 /// 设计器支持所需的方法 - 不要使用代码编辑器修改
96
97 /// 此方法的内容。
98
99 /// </summary>
100
101 private void InitializeComponent()
102
103 {
104
105 this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
106
107 this.btnAdmin.Click += new System.EventHandler(this.btnAdmin_Click);
108
109 this.btnUser.Click += new System.EventHandler(this.btnUser_Click);
110
111 this.Load += new System.EventHandler(this.Page_Load);
112
113
114
115 }
116
117 #endregion
118
119
120
121 private void btnLogin_Click(object sender, System.EventArgs e)
122
123 {
124
125 MyPrincipal principal = new MyPrincipal(tbxUserID.Text,tbxPassword.Text);
126
127 if(!principal.Identity.IsAuthenticated)
128
129 {
130
131 lblLoginMessage.Text = "用户名或密码不正确";
132
133 Panel1.Visible = false;
134
135 }
136
137 else
138
139 {
140
141 // 如果用户通过验证,则将用户信息保存在缓存中,以备后用
142
143 // 在实际中,朋友们可以尝试使用用户验证票的方式来保存用户信息,这也是.NET内置的用户处理机制
144
145 Context.User = principal;
146
147 Hashtable userMessage = new Hashtable();
148
149 userMessage.Add("UserID",tbxUserID.Text);
150
151 userMessage.Add("UserPassword",tbxPassword.Text);
152
153 Context.Cache.Insert("UserMessage",userMessage);
154
155 lblLoginMessage.Text = tbxUserID.Text + "已经登录";
156
157 Panel1.Visible = true;
158
159 }
160
161 }
162
163
164
165 private void btnAdmin_Click(object sender, System.EventArgs e)
166
167 {
168
169 // 验证用户的Role中是否包含Admin
170
171 if(Context.User.IsInRole("Admin"))
172
173 {
174
175 lblRoleMessage.Text = "用户" + ((MyPrincipal)Context.User).Identity.Name + "属于Admin组";
176
177 }
178
179 else
180
181 {
182
183 lblRoleMessage.Text = "用户" + Context.User.Identity.Name + "不属于Admin组";
184
185 }
186
187 }
188
189
190
191 private void btnUser_Click(object sender, System.EventArgs e)
192
193 {
194
195 // 验证用户的Role中是否包含User
196
197 if(Context.User.IsInRole("User"))
198
199 {
200
201 lblRoleMessage.Text = "用户" + Context.User.Identity.Name + "属于User组";
202
203 }
204
205 else
206
207 {
208
209 lblRoleMessage.Text = "用户" + Context.User.Identity.Name + "不属于User组";
210
211 }
212
213 }
214
215 }
216
217 }
218
219
代码部分介绍完了,朋友们可以自己试试来看到效果,在这个例子中很多地方都为了方便而直接给予赋值,在实际应用中,这些将是从数据库或从其它配置文件中得到,而这种方法的可扩展性是非常高的,我们可以根据自己的需要来扩展MyIprincipal和MyIdentity类的功能。比如我们可以添加一个IsInPermission来使用户不仅属于角色,每个角色还可以拥有不同的权限。在本例中,在用户验证过后是通过使用缓存来保存已验证用户的信息的,我们还可以尝试使用用户验证票的方式来实现。