为什么开发自定义Membership和Role的Provider
怎么说呢,原因可能很多,下面列出了部分原因:
你使用了其它数据库(也就是不是SQL Server或者Access数据库)来存放你的数据
你使用了一些非标准的数据库而这些数据库并没有内置的membership和role Providers模型
你想要执行数据在包含和检索过程具有加密的功能
你想要自己写数据库的处理而非以来于membership和role Provider模型
需求
现在让我们决定自定的membership和role Provider需要什么要求:
我们想要使用我们自己的数据库来存放membership和role信息,这就意味者我们不需要使用中间数据存储应用程序的名称
我们使用自定义的Users表来存放成员关系的详细信息
我们使用自定义的Roles表存放系统里可以使用的角色
我们使用UserRoles表来映射User-Role的关联
为了简化本示例,我们不再提供如下功能
密码的“加密-解密”功能
用户注册时主要输入用户名,密码和邮件即可,不用输入安全提问和答案
我们不需要诸如密码恢复,账号锁定等功能
数据访问
这里我们使用BinaryIntellect DatabaseHelper 来完成本模块的数据库访问
建立Web站点
首先,建立一个Web站点,然后在App_Code目录学建立两个类:MyMembershipProvider 和MyRoleProvider。为了简化应用程序,我们建立webSite本身需要的必要类。在实际的应用中,你可以建立单独的类来包含这些类。
配置Web应用程序使用自定义Providers
打开web.config并增加如下的标记:
<membership defaultProvider="mymembershipprovider">
<providers>
<add name="mymembershipprovider"
type="MyMembershipProvider"
connectionStringName="connstr"/>
</providers>
</membership>
<roleManager enabled="true" defaultProvider="myrolesprovider">
<providers>
<add name="myrolesprovider"
type="MyRolesProvider"
connectionStringName="connstr"/>
</providers>
</roleManager>
在这两段代码里,我们告诉ASP.NET系统使用MyMembershipProvider类来作为成员关系的提供者,使用MyRolesProvider类来作为角色的提供者,建立自定义成员关系的Provider
回忆一下第二部分介绍的程序关系Provider模型,我们需要从System.Web.Security.MembershipProvider 类派生出自定义的成员类
MembershipProvider类又是从ProviderBase类继承而来。MembershipProvider类包含几个抽象的方法,你可以在你自定义的类中使用这些方法
如果你使用的是VS.NET开发环境,那么你可以减轻开发的工作。在MembershipProvider类的定义处右击属性,转到MembershipProvider类的定义可以看到其属性/方法
下面列出了改类属性/方法以及意义的列表
(天天注:这里的意义翻译并没有取之原文,因为中文版本的MSDN已经提供了,你可以查看Member Provider类的成员列表)
|
属性/方法 |
意义 |
|
Initialize()* |
初始化提供程序。在这里获取web.config里数据库链接字符串的值,我们需要在自己的类里进行数据库处理 |
|
Name* |
这里程序自定义Provider的名称。 |
|
CreateUser()* |
建立一个用户 |
|
UpdateUser()* |
保护注册用户资料的更改 |
|
DeleteUser()* |
删除一个用户 |
|
GetUser()* |
获取一个MembershipUser对象实例 |
|
GetAllUsers()* |
获取MembershipUserCollection里用户的集合 |
|
ChangePassword()* |
更改密码 |
|
GetPassword()* |
从数据源获取指定用户名所对应的密码。 |
|
ValidateUser()* |
验证数据源中是否存在指定的用户名和密码。 |
|
EnablePasswordReset* |
指示成员资格提供程序是否配置为允许用户重置其密码。 |
|
EnablePasswordRetrieval* |
指示成员资格提供程序是否配置为允许用户检索其密码。 |
|
RequiresQuestionAndAnswer* |
获取一个值,该值指示成员资格提供程序是否配置为要求用户在进行密码重置和检索时回答密码提示问题。 |
|
RequiresUniqueEmail* |
获取一个值,指示成员资格提供程序是否配置为要求每个用户名具有唯一的电子邮件地址。 |
|
ApplicationName |
使用自定义成员资格提供程序的应用程序的名称。 |
|
MaxInvalidPasswordAttempts |
获取锁定成员资格用户前允许的无效密码或无效密码提示问题答案尝试次数。 |
|
MinRequiredNonAlphanumericCharacters |
获取有效密码中必须包含的最少特殊字符数。 |
|
MinRequiredPasswordLength |
获取密码所要求的最小长度。 |
|
ChangePasswordQuestionAndAnswer() |
处理更新成员资格用户的密码提示问题和答案的请求。 |
|
FindUsersByEmail() |
获取一个成员资格用户的集合,这些用户的电子邮件地址包含要匹配的指定电子邮件地址。 |
|
FindUsersByName() |
获取一个成员资格用户的集合,这些用户的用户名包含要匹配的指定用户名。 |
|
GetNumberOfUsersOnline() |
获取当前访问该应用程序的用户数。 |
|
GetUser() |
从数据源获取成员资格用户的信息。 |
|
GetUserNameByEmail() |
利用邮件获取用户名 |
|
PasswordAttemptWindow |
指示密码输入间隔的时间 |
|
PasswordFormat |
密码格式,例如明文,Hash表等 |
|
PasswordStrengthRegularExpression |
密码使用的正则表达式 |
|
ResetPassword() |
重置用户密码 |
|
UnlockUser() |
接锁用户 |
在我们的代码里,我们将重载上面列出的前面具有“*”标记的属性或者方法,其它的属性方法只简单的抛出一个“没有执行”的异常
完整的源代码请见下载文件里的MyMembershipProvider.cs,部分代码如下
(天天注:这里引用了更多的源代码)
using BinaryIntellect.DataAccess;2

3
public class MyMembershipProvider:MembershipProvider4
{5
private DatabaseHelper db = null;6
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)7
{8
string connstr = ConfigurationManager.ConnectionStrings[config["connectionStringName"]].ConnectionString;9
db = new DatabaseHelper(connstr);10
}11

12
public override string Name13
{ 14
get 15
{ 16
return "MyMembershipProvider"; }17
}18

19
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)20
{21
MembershipUser user = new MembershipUser(Name, username, providerUserKey, email, passwordQuestion, null, isApproved, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);22
string sql = "INSERT INTO USERS(USERNAME,PASSWORD,EMAIL,ISACTIVE) VALUES(@UID,@PWD,@EMAIL,@ISACTIVE)";23
db.AddParameter("@UID", username);24
db.AddParameter("@PWD", password);25
db.AddParameter("@EMAIL", email);26
db.AddParameter("@ISACTIVE", (isApproved == true ? "Y" : "N"));27
int i = db.ExecuteNonQuery(sql);28
if (i > 0)29
{30
status = MembershipCreateStatus.Success;31
return user;32
}33

34
else35
{36
status = MembershipCreateStatus.ProviderError;37
return null;38
}39
}40

41
public override void UpdateUser(MembershipUser user)42
{43
string sql = "UPDATE USERS SET EMAIL=@EMAIL,ISACTIVE=@ISACTIVE WHERE USERNAME=@UID";44
db.AddParameter("@EMAIL", user.Email);45
db.AddParameter("@ISACTIVE", (user.IsApproved ? "Y" : "N"));46
db.AddParameter("@UID", user.UserName);47
int i = db.ExecuteNonQuery(sql);48
}49

50
public override bool DeleteUser(string username, bool deleteAllRelatedData)51
{52
string sql = "DELETE FROM USERS WHERE USERNAME=@UID";53
db.AddParameter("@UID", username);54
int i = db.ExecuteNonQuery(sql);55
if (i > 0)56
return true;57
else58
return false;59
}60

61
public override MembershipUser GetUser(string username, bool userIsOnline)62
{63
MembershipUser user = null;64

65
string sql = "SELECT * FROM USERS WHERE USERNAME=@UID AND ISACTIVE='Y'";66

67
db.AddParameter("@UID", username);68

69
SqlDataReader reader = (SqlDataReader)db.ExecuteReader(sql);70

71
while (reader.Read())72
{73
user = new MembershipUser(Name, reader.GetString(reader.GetOrdinal("username")), null, reader.GetString(reader.GetOrdinal("email")), null, null, (reader.GetString(reader.GetOrdinal("isactive")) == "Y" ? true : false), false, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue);74
}75

76
reader.Close();77
return user;78
}79

80
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)81
{82
MembershipUserCollection users = new MembershipUserCollection();83

84
object obj=db.ExecuteScalar("SELECT COUNT(*) FROM USERS");85

86
int reccount=0;87

88
if (obj != null)89
reccount = (int)obj;90

91
SqlDataReader reader = (SqlDataReader)db.ExecuteReader("SELECT * FROM USERS ORDER BY USERNAME");92

93
while (reader.Read())94
{95
MembershipUser user = new MembershipUser(Name, reader.GetString(reader.GetOrdinal("username")), null, reader.GetString(reader.GetOrdinal("email")), null, null, (reader.GetString(reader.GetOrdinal("isactive")) == "Y" ? true : false), false, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue);96
users.Add(user);97
}98
reader.Close();99
totalRecords = reccount;100
return users;101
}102

103
#endregion104

105
Password Management132

133
Authentication157

158
Provider Configuration192
}193

194

建立自定义的角色Provider
该类完成列表请参考MSDN:RoleProvider
|
属性/方法 |
意义 |
|
Initialize()* |
初始化提供程序。 |
|
Name* |
显示自定义Provider的名称 |
|
CreateRole* |
在数据源中为已配置的 applicationName 添加一个新角色。 |
|
DeleteRole* |
从数据源中移除已配置的 applicationName 的角色。 |
|
GetAllRoles* |
获取已配置的 applicationName 的所有角色的列表。 |
|
RoleExists* |
获取一个值,该值指示指定角色名是否已存在于已配置的 applicationName 的角色数据源中。 |
|
AddUsersToRoles* |
将指定用户名添加到已配置的 applicationName 的指定角色名。 |
|
RemoveUsersFromRoles* |
移除已配置的 applicationName 的指定角色中的指定用户名。 |
|
GetRolesForUser* |
获取指定用户对于已配置的 applicationName 所属于的角色的列表。 |
|
GetUsersInRole* |
获取属于已配置的 applicationName 的指定角色的用户的列表。 |
|
IsUserInRole* |
获取一个值,指示指定用户是否属于已配置的 applicationName 的指定角色。 |
|
ApplicationName |
获取或设置要存储和检索其角色信息的应用程序的名称。 |
|
FindUsersInRole |
获取属于某个角色且与指定的用户名相匹配的用户名的数组。 |
在我们的代码里,我们将重载上面列出的前面具有“*”标记的属性或者方法,其它的属性方法只简单的抛出一个“没有执行”的异常
下面列出了部分代码
using System;2

3
using System.Data;4

5
using System.Data.SqlClient;6

7
using System.Configuration;8

9
using System.Web;10

11
using System.Web.Security;12

13
using System.Web.UI;14

15
using System.Web.UI.WebControls;16

17
using System.Web.UI.WebControls.WebParts;18

19
using System.Web.UI.HtmlControls;20

21
using BinaryIntellect.DataAccess;22

23
using System.Collections;24

25
public class MyRolesProvider:RoleProvider26

27
{28

29
private DatabaseHelper db = null;30

31
General58

59
Role Management144

145
Users and Roles测试自定义Provider
在你下载的页面里包含了四个Web窗体--default.aspx,Login.aspx,RoleManager.aspx和UserRoles.aspx。前面两个用于测试成员关系的Provider模型,后面两个用户测试角色的Provider模型。
我们使用了ASP.NET2.0提供的Membership和Roles的基本功能,这些类会使用我们自定义的Provider来完成相应的工作
总结
在本文我们我们可以看到自定义Membership和Role是多么的简单。你可以扩展该功能来适用你的应用程序,你还可以扩展诸如加密解密等功能


浙公网安备 33010602011771号