ASP.NET中默認的MembershipProvider和RoleProvider是Sql Server的,可是默認的提供類有時候不能知足要求,如數據庫不是Sql Server,或者想使用本身的數據庫表結構等緣由不想使用自帶的提供類,能夠自定義提供類web
在web.config中定義forms驗證的路徑和自定義提供類的名稱數據庫
<?xml version="1.0"?> <configuration> <system.web> <compilation debug="true" targetFramework="4.0"/> <authentication mode="Forms"> <forms loginUrl="~/Login.aspx" timeout="60" > </forms> </authentication> <membership defaultProvider="AccessMembershipProvider"> <providers> <clear /> <add name="AccessMembershipProvider" type="WebApplication1.CustomProvider.AccessMembershipProvider" applicationName="/" /> </providers> </membership> <roleManager enabled="true" defaultProvider="InProcRoleProvider" > <providers> <clear/> <add name="InProcRoleProvider" type="WebApplication1.CustomProvider.InProcRoleProvider" applicationName="/"/> </providers> </roleManager> <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/> </system.web> <location path="member"> <system.web> <authorization> <allow roles="member,admin"/> <deny users="*"/> </authorization> </system.web> </location> <location path="admin"> <system.web> <authorization> <allow roles="admin"/> <deny users="*"/> </authorization> </system.web> </location> </configuration>
其中定義了admin目錄只能由admin的role成員訪問,member目錄能夠由admin和member成員訪問app
MembershipProvider:ide
實現了ValidateUser和幾個必要的驗證屬性(MinRequiredPasswordLength等)就能夠使登陸控件正常使用,其餘註冊,密碼修改等控件實現對應方法便可ui
這裏我使用了Access做爲數據源spa
先定義Access數據操做對象,鏈接串是固定的,實際狀況應該是根據配置文件讀取,傳遞進debug
public class DaoAccess { private string conStr; public DaoAccess() { conStr = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Database.mdb"; } private int ExecuteNonQuery(string query) { var con = new OleDbConnection(conStr); int rst = -1; OleDbCommand cmd = new OleDbCommand(query, con); try { con.Open(); rst = cmd.ExecuteNonQuery(); } finally { con.Close(); } return rst; } public bool CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer) { string query = string.Format("insert into UserInfo(Name,[Password],Email,PasswordQuestion,PasswordAnswer) values('{0}','{1}','{2}','{3}','{4}')", username, password, email, passwordAnswer, passwordQuestion); return ExecuteNonQuery(query)>0; } public bool ChangePassword(string username, string oldPassword, string newPassword) { string query = string.Format("update UserInfo set [Password]='{0}' where Name='{1}' and [Password]='{2}'", newPassword, username, oldPassword); return ExecuteNonQuery(query) > 0; } public UserInfo GetUserByName(string username) { string query = string.Format("select * from UserInfo where Name='{0}'", username); OleDbDataAdapter ada = new OleDbDataAdapter(query, new OleDbConnection(conStr)); DataTable dt = new DataTable(); ada.Fill(dt); var userlist= dt.ConvertToList<UserInfo>(); if (userlist.Count > 0) return userlist[0]; return null; }
而後自定義的AccessMembershipProvider中調用數據訪問類來讀取和寫入access3d
public class AccessMembershipProvider:MembershipProvider { private string providerName ; private DaoAccess adapter = new DaoAccess(); public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) { providerName = name; base.Initialize(name, config); } public override string ApplicationName { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public override bool ChangePassword(string username, string oldPassword, string newPassword) { return adapter.ChangePassword(username, oldPassword, newPassword); } public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) { throw new NotImplementedException(); } public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) { if (!adapter.CreateUser(username, password, email, passwordAnswer, passwordQuestion)) { status = MembershipCreateStatus.DuplicateUserName; } else { status = MembershipCreateStatus.Success; } var now=DateTime.Now; MembershipUser user = new MembershipUser(providerName, username, "", email, password, "" , true, true, now, now, now, now, now); return user; } public override bool DeleteUser(string username, bool deleteAllRelatedData) { throw new NotImplementedException(); } public override bool EnablePasswordReset { get { throw new NotImplementedException(); } } public override bool EnablePasswordRetrieval { get { throw new NotImplementedException(); } } public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } public override int GetNumberOfUsersOnline() { throw new NotImplementedException(); } public override string GetPassword(string username, string answer) { throw new NotImplementedException(); } public override MembershipUser GetUser(string username, bool userIsOnline) { var user= adapter.GetUserByName(username); if (user == null) return null; var now=DateTime.Now; return new MembershipUser(providerName, user.Name, user.UserId, user.Email, user.PasswordQuestion, "", true, false, now, now, now, now, now); } public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) { throw new NotImplementedException(); } public override string GetUserNameByEmail(string email) { throw new NotImplementedException(); } public override int MaxInvalidPasswordAttempts { get { return 20; } } public override int MinRequiredNonAlphanumericCharacters { get { return 0; } } public override int MinRequiredPasswordLength { get { return 6; } } //獲取在鎖定成員資格用戶以前容許的最大無效密碼或無效密碼提示問題答案嘗試次數的分鐘數。 public override int PasswordAttemptWindow { get { return 20; } } public override MembershipPasswordFormat PasswordFormat { get { return MembershipPasswordFormat.Clear; } } public override string PasswordStrengthRegularExpression { get { throw new NotImplementedException(); } } public override bool RequiresQuestionAndAnswer { get { return true; } } public override bool RequiresUniqueEmail { get { return false; } } public override string ResetPassword(string username, string answer) { throw new NotImplementedException(); } public override bool UnlockUser(string userName) { throw new NotImplementedException(); } public override void UpdateUser(MembershipUser user) { throw new NotImplementedException(); } public override bool ValidateUser(string username, string password) { var user= adapter.GetUserByName(username); if (user == null) return false; return user.Password == password; } }
RoleProvider:code
實現了IsUserInRole方法,就能夠使role的驗證功能正常,若是要其餘增長刪除等功能,實現對應方法便可orm
public class InProcRoleProvider : RoleProvider { //存放用戶權限的字典 Dictionary<string, List<string>> _Users = new Dictionary<string, List<string>>(); //權限的列表 List<string> _Roles = new List<string>(); public override void AddUsersToRoles(string[] usernames, string[] roleNames) { CheckRoles(roleNames); foreach (var username in usernames) { foreach (var roleName in roleNames) AddUserToRole(username, roleName); } } private void CheckRoles(string[] roleNames) { foreach (var newRole in roleNames) { if (!_Roles.Any(item => item == newRole)) throw new Exception(newRole + " 不存在"); } } private void AddUserToRole(string username, string roleName) { if (_Users.ContainsKey(username)) { var roles = _Users[username]; if (roles.Any(name => name == roleName)) return; roles.Add(roleName); } else { _Users.Add(username, new List<string>() { roleName }); } } public override string ApplicationName { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public override void CreateRole(string roleName) { _Roles.Add(roleName); } public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) { _Roles.Remove(roleName); _Users= _Users.Where(item => { return item.Value.Any(v => v == roleName) == false; }) .ToDictionary(item => item.Key,item=>item.Value); return true; } public override string[] FindUsersInRole(string roleName, string usernameToMatch) { throw new NotImplementedException(); } public override string[] GetAllRoles() { throw new NotImplementedException(); } public override string[] GetRolesForUser(string username) { if (_Users.ContainsKey(username)) return _Users[username].ToArray(); return new string[0]; } public override string[] GetUsersInRole(string roleName) { throw new NotImplementedException(); } public override bool IsUserInRole(string username, string roleName) { if (_Users.ContainsKey(username)) { return _Users[username].Any(role=>role==roleName); } return false; } public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); } public override bool RoleExists(string roleName) { return _Roles.Any(role => role == roleName); } }
爲了簡化代碼,InProcRoleProvider用了內存做爲存放用戶的role數據
在Global.asax的Application_Start方法中初始化
void Application_Start(object sender, EventArgs e) { if(!Roles.RoleExists("admin")) Roles.CreateRole("admin"); if (!Roles.RoleExists("member")) Roles.CreateRole("member"); }