前言:
最近在学习ASP.NET,发现了几个有趣的类,比如自定义用户配置提供程序ProfileProvider,成员提供程序MembershipProvider,角色管理RoleProvider,会话状态SessionStateStoreProvider,这几个类经常作为权限相关设置,但是默认这几个类都必须使用定制的数据库,因此造成诸多限制。
但如果重写这些类,然后配合.NET原有的API来使用,这样一来用着方便,二来由于提供程序是自定义的,能够满足自己的要求。
于是小弟我试着重写这些类,分享自己的一些心得体会,希望各位前辈能够多多指教啦
前言
最近在学习ASP.NET,发现了几个有趣的类,比如自定义用户配置提供程序ProfileProvider,成员提供程序MembershipProvider,角色管理RoleProvider,会话状态SessionStateStoreProvider,这几个类经常作为权限相关设置,但是默认这几个类都必须使用定制的数据库,因此造成诸多限制
但如果重写这些类,然后配合.NET原有的API来使用,这样一来用着方便,二来由于提供程序是自定义的,能够满足自己的要求
于是小弟我试着重写这些类,分享自己的一些心得体会,希望各位前辈能够多多指教啦
实现自定义成员提供程序MembershipProvider
一。说明
在ASP.NET中,在WEB.CONFIG中进行成员管理的相关配置,就可以在页面中使用许多成员相关的控件,比如:
Login控件

CreateUserWizard控件

LoginView,LoginName,LoginStatus控件

上次写实现自定义用户配置提供程序ProfileProvider的时候,和就提出过,如果用的SQL数据库,使用原来默认的提供程序更方便,确实,如果使用SQL,直接使用默认的提供程序比自己再写个方便多了。所以,这次重写,使用XML文件作为存储的介质,才能够体现重写的优势----因为默认的提供程序不支持XML(-_-#)。
在重写之前,首先要了解该类的一些需要重写的方法和属性,新类必须继承自MembershipProvider类
属性:
string ApplicationName//应用程序名
string Description//一些描述
bool EnablePasswordReset//是否允许用户重置其密码
bool EnablePasswordRetrieval//是否允许用户检索其密码
int MaxInvalidPasswordAttempts//密码尝试次数
int MinRequiredNonAlphanumericCharacters//密码得最少特殊字符
int MinRequiredPasswordLength//密码的最少长度
int PasswordAttemptWindow//用户因为密码错误被锁定的最大分钟数
MembershipPasswordFormat PasswordFormat//存密码的格式
string PasswordStrengthRegularExpression//计算密码的正则表达式
bool RequiresQuestionAndAnswer//是否在密码重置或检索时验证问题答案
bool RequiresUniqueEmail//是否E-mail地址唯一
方法:
void Initialize(string name, System.Collections.Specialized.NameValueCollection config)//初始化
bool ValidateUser(string username, string password)//验证用户密码
MembershipUser GetUser(string username, bool userIsOnline)//根据用户名得到用户信息
MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)//得到所有的用户信息(前两个参数是分页,最后那个是用户总数)
string GetUserNameByEmail(string email)//根据EMAIL得到用户信息
MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)//创建一个用户
int GetNumberOfUsersOnline()//获取在线人数
MembershipUser GetUser(object providerUserKey, bool userIsOnline)//根据用户标识来获取用户信息
bool ChangePassword(string username, string oldPassword, string newPassword)//修改密码
bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)//修改问题和答案
bool DeleteUser(string username, bool deleteAllRelatedData)//删除用户
MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)//根据EAMIL获取多个用户信息
MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) //根据用户名来获取多个用户信息
string GetPassword(string username, string answer)//获取密码
bool UnlockUser(string userName)//解锁用户
void UpdateUser(MembershipUser user)//更新用户
string ResetPassword(string username, string answer)//重设密码
二。实现
首先建立一个名为Users.xml的XML文件,结构如下
<?xml version="1.0" encoding="utf-8"?>
<Users>
<User Name="Test1">
<PassWord>132123</PassWord>
<Email>asd@asd.com</Email>
<PassWordQuestion>你是?</PassWordQuestion>
<PassWordAnswer>猪</PassWordAnswer>
<IsApproved>true</IsApproved>
<IsLockedOut>false</IsLockedOut>
<CreatingDate>2009/3/8 15:35</CreatingDate>
<LastLoginDate>2009/3/8 15:35</LastLoginDate>
<LastActivityDate>2009/3/8 15:35</LastActivityDate>
<LastPassWordChangedDate>2009/3/8 15:35</LastPassWordChangedDate>
<LastLockOutDate>2009/3/8 15:35</LastLockOutDate>
</User>
</Users>
然后重写这个类,这里只列出一些关键代码

Code
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Xml;
/// <summary>
///OverrideMembershipProvider 的摘要说明
/// </summary>
public class OverrideMembershipProvider:MembershipProvider
{
public OverrideMembershipProvider()
{
//
//TODO: 在此处添加构造函数逻辑
//
}
protected XmlDocument GetDoc()//专门读取XML文件并返回一个XmlDocument对象的方法,自定义的一个方法,并非继承自MembershipProvider
{
XmlDocument doc = new XmlDocument();
doc.Load(System.Web.Hosting.HostingEnvironment.MapPath("~/Users.xml"));
return doc;
}
protected void SaveDoc(XmlDocument doc)//保存对XML文件的修改(比如添加用户),自定义的一个方法,并非继承自MembershipProvider
{
doc.Save(System.Web.Hosting.HostingEnvironment.MapPath("~/Users.xml"));
}
private string applicationName;
public override string ApplicationName//应用程序名
{
get
{
return applicationName;
}
set
{
applicationName = value;
}
}
public override string Description//一些描述
{
get
{
return "没啥说的吧
.";
}
}
public override bool EnablePasswordReset//是否允许用户重置其密码
{
get { return false; }
}
public override bool EnablePasswordRetrieval//是否允许用户检索其密码
{
get { return false; }
}
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
applicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;
base.Initialize(name!=null?name:"OverrideMembershipProvider", config);
}
public override bool ValidateUser(string username, string password)
{
if (GetDoc().SelectSingleNode("//User[@Name='" + username + "' and PassWord='" + password + "']") == null)
{
return false;
}
else
{
return true;
}
}
public override MembershipUser GetUser(string username, bool userIsOnline)
{
XmlNode x = GetDoc().SelectSingleNode("//User[@Name='" + username + "']");
if (x == null)
return null;
else
{
MembershipUser user = new MembershipUser(Name, x.Attributes["Name"].Value, null, x["Email"].InnerText, x["PassWordQuestion"].InnerText,string.Empty, Convert.ToBoolean(x["IsLockedOut"].InnerText), Convert.ToBoolean(x["IsApproved"].InnerText), Convert.ToDateTime(x["CreatingDate"].InnerText), Convert.ToDateTime(x["LastLoginDate"].InnerText), Convert.ToDateTime(x["LastActivityDate"].InnerText), Convert.ToDateTime(x["LastPassWordChangedDate"].InnerText), Convert.ToDateTime(x["LastLockOutDate"].InnerText));
return user;
}
}
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
XmlNodeList xl = GetDoc().DocumentElement.ChildNodes;
totalRecords = xl.Count;
if (pageIndex * pageSize > xl.Count) return null;
else
{
MembershipUserCollection mc = new MembershipUserCollection();
for (int i = pageIndex * pageSize ; i < xl.Count&&pageSize>0; i++,pageSize--)
{
XmlNode x = xl[i];
mc.Add(new MembershipUser(Name, x.Attributes["Name"].Value, null, x["Email"].InnerText, x["PassWordQuestion"].InnerText, null, Convert.ToBoolean(x["IsLockedOut"].InnerText), Convert.ToBoolean(x["IsApproved"].InnerText), Convert.ToDateTime(x["CreatingDate"].InnerText), Convert.ToDateTime(x["LastLoginDate"].InnerText), Convert.ToDateTime(x["LastActivityDate"].InnerText), Convert.ToDateTime(x["LastPassWordChangedDate"].InnerText), Convert.ToDateTime(x["LastLockOutDate"].InnerText)));
}
return mc;
}
}
public override string GetUserNameByEmail(string email)
{
XmlNode x = GetDoc().SelectSingleNode("//User[Email='" + email + "']");
if (x == null)
return null;
else
return x.Attributes["Name"].Value;
}
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
XmlDocument x=GetDoc();
if (x.SelectSingleNode("//User[@Name='" + username + "']") != null)
{
status = MembershipCreateStatus.DuplicateUserName;
return null;
}
XmlElement xe = x.DocumentElement;
MembershipUser user = new MembershipUser(Name, username, null, email, passwordQuestion, "", isApproved, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
xe.InnerXml+= " <User Name=\""+username+"\">"+
"<PassWord>"+password+"</PassWord>"+
"<Email>"+email+"</Email>"+
"<PassWordQuestion>" + passwordQuestion + "</PassWordQuestion>" +
"<PassWordAnswer>" + passwordAnswer + "</PassWordAnswer>" +
"<IsApproved>" + isApproved + "</IsApproved>" +
"<IsLockedOut>false</IsLockedOut>" +
"<CreatingDate>" +user.CreationDate.ToString() + "</CreatingDate>" +
"<LastLoginDate>" + user.LastLoginDate.ToString() + "</LastLoginDate>" +
"<LastActivityDate>" +user.LastActivityDate.ToString() + "</LastActivityDate>" +
"<LastPassWordChangedDate>" + user.LastPasswordChangedDate.ToString() + "</LastPassWordChangedDate>" +
"<LastLockOutDate>" + user.LastLockoutDate.ToString() + "</LastLockOutDate></User>";
SaveDoc(x);
status = MembershipCreateStatus.Success;
return user;
}
}
最后,修改WEB.CONFIG,大功告成
<membership defaultProvider="aaaa">
<providers>
<add name="aaaa" type="OverrideMembershipProvider"/>
</providers>
</membership>
<authentication mode="Forms">
<forms loginUrl="Default.aspx"></forms>
</authentication>
接下来就可以享用这些控件了

附:源码下载
(说明:Class1.cs相当于一个业务逻辑类,只有一个方法,用于返回所有的用户集合,主要是为了配合ObjectDataSource(Default2.aspx页面会使用并显示所有用户信息)
OverrideMembershipProvider.cs则是重写后的提供程序类,并没有把每个属性和方法都实现,只实现了一些关键的部分
Default.aspx是登陆界面
Default2.aspx显示所有用户信息
Default3.aspx建立新用户
Default4.aspx根据登陆情况显示用户信息,并可以登陆登出)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?