轉自:http://www.programbbs.com/doc/2988.htm
轉向Asp.net 2.0,如果單單看Asp.net 2.0的例子和SDK,相信你一定對系統自帶的Login控件有比較深刻的印象。Asp.Net 2.0的Login控件不用你寫一行檢測用戶輸入是否合法的程序代碼及相關查詢數據庫的SQL腳本,只需把相應的控件拖到Web表單中,即可完成用戶登陸,創建用戶,用戶角色管理,修改密碼用戶詳細情況,取回密碼等功能模塊。
Login控件看上去近乎完美,而我們現在手頭正好來了一個項目要求采用Asp.net 2.0開發,而該項目也要求有登陸,用戶管理,權限管理,修改密碼等功能,相信絕大多數人都會考慮使用Login控件來快速搞定這些要求。于是乎,大家拿出以前的教學例子,試著分析較深一層的代碼,看看該在哪里對Login控件修改一番,讓它滿足手頭項目已設計好的數據庫表結構。結果發現,除了aspx文件里面可以對Login控件的外觀,提示文字可以自定義外,cs文件中愣是找不到一行代碼,然后繼續翻MSDN和Google,終于知道,要在自己的項目中直接使用系統自帶的Login控件,需要做2項修改工作:
1、根據你選用的數據庫,修改Web.config中相應的connectionStrings。系統默認的數據庫是SQL Server 2005 Express,如果我們的數據庫是Access/SQL2000/2005/Oracle,當然要大改一番了。
2、改完Web.config還不夠,我們還得執行C:\WINNT\Microsoft.NET\Framework\v2.0.507\aspnet_sqlreg.exe注冊你的sql server,該程序的作用是在你的數據庫中建立Login控件需要的所有資源(大約有上十個表,三十多條存儲過程,上十個視圖等等),如果你使用的是access/orcale,或者是其他格式的數據庫,那你自己去Google相應的SQL腳本吧。
OK,想到Login控件幫你節省的工作量,相信不少人都會咬著牙完成上面的2項工作。完成上面2項工作后,大家接著讀項目需求,發現有用戶組管理和權限管理,幸好開發資料上提到Login控件集成的Role角色管理模塊正好與之對應,不過以后我們創建一個用戶后,還要再進入一個頁面給用戶選擇所屬用戶組,當然,采用Role的話,我們可以設定一個用戶同時屬于多個用戶組,貌似功能很強大喲。繼續讀項目需求,發現這些項目的用戶對象還有不少Login控件中沒有的屬性要保存,回頭再去翻MSDN,發現Profile可以幫我們解決這個問題。
嗯,除開使用Login控件,運行aspnet_sqlreg.exe幫我們建立的上十個表,三十多條存儲過程,上十個視圖等,我們再不用建表保存用戶的任何信息了,以后我們只用在Web.config文件和相應的cs代碼中加上Role和Profile的處理代碼,即可完成該項目的登陸,用戶管理,密碼修改功能。算算投入查MSDN,Google及修改Web.config文件和相應的cs代碼的時間,相信原來自己寫過自定義Login控件的朋友已經準備發誓再也不碰Asp.net 2.0自帶的Login控件了。
其實,我們完全有更簡潔通用的辦法來重用Asp.net 2.0自帶的Login控件,即只用它最基本的登陸及修改密碼功能,這2個基本功能照舊從工具箱拖個控件出來往Web表單上一扔即可,一行代碼都不多加。其他的用戶/用戶組管理,權限管理不用扯上Login控件,數據庫想用什么產品就用什么產品,mysql/db2/infomax來者不拒;表結構想怎么設計就怎么設計,E-R圖,UML圖直接照搬就成;用戶/用戶組管理和權限管理模塊想怎么規定就怎么規定,自關聯,無限分級都行。總之一句話:讓Login控件附帶的上十個表,三十多條存儲過程,上十個視圖見鬼去吧。
下面細說實現方法,Asp.net 2.0的Login控件用到了3個類來從數據庫中獲取相應的數據,分別是MemberShipprovider,RoleProvider及ProfileProvider,系統自帶的這3個類的方法的代碼被隱藏起來了,盡管沒公開,但實際上就是使用我上面一直念叨的上十個表,三十多條存儲過程,上十個視圖。不管你用什么數據庫,只要想使用Login控件的所有功能,必須保證該數據庫中有與之對應的十來個表,三十多條存儲過程,十來個視圖。
當然,MS的架構設計師也不是某些人想象中的那么無能,上面的這三個類其實都是抽象類,系統的Login控件實際調用的是從這3個類派生出來的針對SQL Server2000/2005的數據操作類,靈活的架構設計正是在這里體現出來。既然MemberShipProvider,RoleProvider及ProfileProvider三大頭是抽象類,那么我們完全可以自定義一個只針對用戶表的username及password2個列操作的MemberShipprovider派生類出來,重寫登陸驗證,修改密碼以及其調用的方法,然后在Web.config中把membership的提供者指定為我們自己寫的MemberShipprovider派生類,這樣我們就可以和原來一樣,把Login控件的登陸和修改密碼2個子控件往Web表單上一拖了事。
下面開始貼代碼,懶的深究的朋友們可以直接把我給出的cs代碼貼回去,建個cs文件放到App_Code目錄下,然后按照后面的Web.config修改相應的connectionStrings和membership即可,以后任何項目要利用Asp.net 2.0的Login控件的登陸和修改密碼都是這樣照葫蘆畫瓢,夠傻瓜吧。
- using System;
- using System.Data;
- using System.Configuration;
- using System.Data.SqlClient;
- using System.Collections.Generic;
- using System.Text.RegularExpressions;
- using System.Data.SqlTypes;
- using System.Web;
- using System.Web.Security;
- /**//**//**//// <summary>
- /// MyMemberShip 的摘要說明
- /// </summary>
- public class MyMemberShip : MembershipProvider
- {
- private bool _requiresQuestionAndAnswer;
- private int _minRequiredPasswordLength;
- public MyMemberShip()
- {
- //
- // TODO: 在此處添加構造函數邏輯
- //
- }
- public override string ApplicationName
- {
- get
- {
- throw new Exception("The method or operation is not implemented.");
- }
- set
- {
- throw new Exception("The method or operation is not implemented.");
- }
- }
- public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
- {
- if (config["requiresQuestionAndAnswer"].ToLower() == "true")
- _requiresQuestionAndAnswer = true;
- else
- _requiresQuestionAndAnswer = false;
- int.TryParse(config["minPasswordLength"], out _minRequiredPasswordLength);
- base.Initialize(name, config);
- }
- public override bool ChangePassword(string username, string oldPassword, string newPassword)
- {
- using (SqlConnection connection = new SqlConnection(DBBase.DBConnectionString))
- {
- SqlCommand command = new SqlCommand();
- command.CommandText = "update [User] set user_pwd=@newpwd where user_name=@name and user_pwd=@oldpwd";
- command.Parameters.AddWithValue("@name", username);
- command.Parameters.AddWithValue("@oldpwd", CryptUtil.GetStringHashValue1(StringUtil.SqlEscape(oldPassword)));
- command.Parameters.AddWithValue("@newpwd", CryptUtil.GetStringHashValue1(StringUtil.SqlEscape(newPassword)));
- command.Connection = connection;
- connection.Open();
- return (int)command.ExecuteNonQuery() > 0 ? true : false;
- }
- //throw new Exception("The method or operation is not implemented.");
- }
- public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override bool DeleteUser(string username, bool deleteAllRelatedData)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override bool EnablePasswordReset
- {
- get { throw new Exception("The method or operation is not implemented."); }
- }
- public override bool EnablePasswordRetrieval
- {
- get { throw new Exception("The method or operation is not implemented."); }
- }
- public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override int GetNumberOfUsersOnline()
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override string GetPassword(string username, string answer)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override MembershipUser GetUser(string username, bool userIsOnline)
- {
- DateTime myDate = DateTime.Today;
- MembershipUser user = new MembershipUser(
- Name, // Provider name
- username, // Username
- null, // providerUserKey
- bobcy@21cn.com, // Email
- String.Empty, // passwordQuestion
- String.Empty, // Comment
- true, // isApproved
- false, // isLockedOut
- DateTime.Now, // creationDate
- DateTime.Now, // lastLoginDate
- DateTime.Now, // lastActivityDate
- DateTime.Now, // lastPasswordChangedDate
- new DateTime(1980, 1, 1) // lastLockoutDate
- );
- return user;
- }
- public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override string GetUserNameByEmail(string email)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override int MaxInvalidPasswordAttempts
- {
- get { throw new Exception("The method or operation is not implemented."); }
- }
- public override int MinRequiredNonAlphanumericCharacters
- {
- get { return 0; }
- }
- public override int MinRequiredPasswordLength
- {
- get { return _minRequiredPasswordLength; }
- }
- public override int PasswordAttemptWindow
- {
- get { throw new Exception("The method or operation is not implemented."); }
- }
- public override MembershipPasswordFormat PasswordFormat
- {
- get { throw new Exception("The method or operation is not implemented."); }
- }
- public override string PasswordStrengthRegularExpression
- {
- get { throw new Exception("The method or operation is not implemented."); }
- }
- public override bool RequiresQuestionAndAnswer
- {
- get { return _requiresQuestionAndAnswer; }
- }
- public override bool RequiresUniqueEmail
- {
- get { throw new Exception("The method or operation is not implemented."); }
- }
- public override string ResetPassword(string username, string answer)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override bool UnlockUser(string userName)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override void UpdateUser(MembershipUser user)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public override bool ValidateUser(string username, string password)
- {
- using (SqlConnection connection = new SqlConnection(DBBase.DBConnectionString))
- {
- SqlCommand command = new SqlCommand();
- command.CommandText = "select count(0) from [User] where user_name=@name and user_pwd=@pwd";
- command.Parameters.AddWithValue("@name", username);
- command.Parameters.AddWithValue("@pwd", password);
- command.Connection = connection;
- connection.Open();
- return ((int)command.ExecuteScalar()) > 0 ? true : false;
- }
- }
- }
Web.Config的membership節這樣寫,connectionStrings和數據庫有關,不同的數據庫差別很大,大家自己Google,我就不列出來了。







如果我們想在用戶驗證登陸成功后做一些額外的處理,可以給登陸控件的登陸按鈕添加一個事件,相應的代碼如下:










