建立使用者帳戶 (C#)
注意
本文撰寫之後,ASP.NET 成員資格提供者已被 ASP.NET 身分識別取代。 強烈建議您將應用程式更新為使用 ASP.NET 身分識別 平臺,而不是本文撰寫時精選的成員資格提供者。 ASP.NET 身分識別的一些優點優於 ASP.NET 成員資格系統,包括 :
- 更好的效能
- 改善擴充性和可測試性
- 支援 OAuth、OpenID Connect 和雙因素驗證
- 宣告型身分識別支援
- 與 ASP.Net Core 的較佳互通性
在本教學課程中,我們將透過 SqlMembershipProvider) 來探索使用成員資格架構 (來建立新的使用者帳戶。 我們將瞭解如何以程式設計方式和透過 ASP 建立新的使用者。NET 的內建 CreateUserWizard 控制項。
簡介
在上述教學 課程中,我們會在資料庫中安裝應用程式服務架構,以新增 和 SqlRoleProvider
所需的 SqlMembershipProvider
資料表、檢視和預存程式。 這會建立本系列中其餘教學課程所需的基礎結構。 在本教學課程中,我們將透過) 來探索使用成員資格架構 (SqlMembershipProvider
來建立新的使用者帳戶。 我們將瞭解如何以程式設計方式和透過 ASP 建立新的使用者。NET 的內建 CreateUserWizard 控制項。
除了瞭解如何建立新的使用者帳戶之外,我們也必須更新我們在表單驗證概觀教學課程中建立的示範網站,然後在表單驗證設定和進階主題教學課程中 增強。 我們的示範 Web 應用程式有一個登入頁面,可針對硬式編碼的使用者名稱/密碼組驗證使用者的認證。 此外, Global.asax
還包含為已驗證的使用者建立自訂 IPrincipal
和 IIdentity
物件的程式碼。 我們將更新登入頁面,以根據成員資格架構驗證使用者的認證,並移除自訂主體和身分識別邏輯。
現在就開始吧!
表單驗證和成員資格檢查清單
開始使用成員資格架構之前,讓我們花一點時間檢閱我們已採取的重要步驟來達到這一點。 在表單型驗證案例中使用成員資格架構時 SqlMembershipProvider
,必須先執行下列步驟,才能在 Web 應用程式中實作成員資格功能:
- 啟用表單型驗證。 如我們在表單驗證概觀中所 討論,表單驗證是藉由編輯
Web.config
和設定<authentication>
元素的mode
屬性來Forms
啟用。 啟用表單驗證後,會檢查每個傳入要求是否有 表單驗證票證,如果存在,則會識別要求者。 - 將應用程式服務架構新增至適當的資料庫。 使用 時,
SqlMembershipProvider
我們需要將應用程式服務架構安裝到資料庫。 此架構通常會新增至保存應用程式資料模型的相同資料庫。 在SQL Server 中建立成員資格架構教學課程探討如何使用aspnet_regsql.exe
工具來完成這項作業。 - 自訂 Web 應用程式的設定,以參考步驟 2 中的資料庫。 在 SQL Server 中建立成員資格架構教學課程示範了兩種方式來設定 Web 應用程式,
SqlMembershipProvider
讓 使用步驟 2 中選取的資料庫:修改LocalSqlServer
連接字串名稱;或將新的註冊提供者新增至成員資格架構提供者清單,以及自訂該新提供者以使用步驟 2 中的資料庫。
建置使用 SqlMembershipProvider
和 表單型驗證的 Web 應用程式時,您必須先執行這三個步驟,再使用 Membership
類別或 ASP.NET 登入 Web 控制項。 由於我們已在先前的教學課程中執行這些步驟,因此我們已準備好開始使用成員資格架構!
步驟 1:新增 ASP.NET 網頁
在本教學課程和下三個教學課程中,我們將檢查各種成員資格相關函式和功能。 我們需要一系列 ASP.NET 網頁,以實作這些教學課程中檢查的主題。 讓我們建立這些頁面,然後建立網站地圖檔案 (Web.sitemap)
。
首先,在名為 Membership
的專案中建立新的資料夾。 接下來,將五個新的 ASP.NET 頁新增至 Membership
資料夾,並將每個頁面與 Site.master
主版頁面連結。 將頁面命名為:
CreatingUserAccounts.aspx
UserBasedAuthorization.aspx
EnhancedCreateUserWizard.aspx
AdditionalUserInfo.aspx
Guestbook.aspx
此時,您的專案方案總管看起來應該類似圖 1 所示的螢幕擷取畫面。
圖 1:已將五個新頁面新增至 Membership
資料夾 (按一下以檢視大小完整的影像)
此時,每個頁面都應該有兩個 Content 控制項,一個用於主版頁面的 ContentPlaceHolders: MainContent
和 LoginContent
。
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent"
Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="LoginContent"
Runat="Server">
</asp:Content>
回想一下, LoginContent
ContentPlaceHolder 的預設標記會顯示登入或登出網站的連結,視使用者是否經過驗證而定。 不過,內容控制項的存在 Content2
會覆寫主版頁面的預設標記。 如表單驗證概觀教學課程中所述 ,這在不想在左側資料行中顯示登入相關選項的頁面很有用。
不過,針對這五個頁面,我們想要顯示 ContentPlaceHolder 的主版頁面預設標記 LoginContent
。 因此,移除 Content 控制項的 Content2
宣告式標記。 這麼做之後,五個頁面的標記應該只包含一個內容控制項。
步驟 2:建立網站地圖
除了最簡單的網站,還需要實作某種形式的導覽使用者介面。 流覽使用者介面可能是網站各種區段連結的簡單列表。 或者,這些連結可以排列成功能表或樹狀檢視。 身為頁面開發人員,建立導覽使用者介面只是本文的一半。 我們也需要一些方法,以可維護且可更新的方式定義網站的邏輯結構。 新增頁面或移除現有的頁面時,我們想要能夠更新單一來源 – 網站地圖 , 並讓這些修改反映在網站的流覽使用者介面上。
這兩項工作 – 定義網站地圖和根據網站地圖實作導覽使用者介面 – 很容易完成,因為網站地圖架構和 ASP.NET 2.0 版中新增的導覽 Web 控制項。 網站地圖架構可讓開發人員定義網站地圖,然後透過程式設計 API 存取網站地圖, (SiteMap
類別) 。 內建導覽 Web 控制項包含 功能表控制項、 TreeView 控制項和 SiteMapPath 控制項。
如同成員資格和角色架構,網站地圖架構是建置在 提供者模型之上。 網站地圖提供者類別的作業是從持續性資料存放區產生類別所使用的 SiteMap
記憶體內部結構,例如 XML 檔案或資料庫資料表。 .NET Framework隨附預設的網站地圖提供者,該提供者會從 XML 檔案 () XmlSiteMapProvider
讀取網站地圖資料,而這是我們將在本教學課程中使用的提供者。 如需一些替代的網站地圖提供者實作,請參閱本教學課程結尾的一節。
預設的網站地圖提供者預期有名為 Web.sitemap
的適當格式 XML 檔案存在根目錄。 由於我們使用這個預設提供者,因此我們需要新增這類檔案,並以適當的 XML 格式定義網站地圖的結構。 若要新增檔案,請以滑鼠右鍵按一下方案總管中的專案名稱,然後選擇 [新增專案]。 從對話方塊中,選擇新增名為 Web.sitemap
之網站地圖類型的檔案。
圖 2:將名為 Web.sitemap
的檔案新增至專案的根目錄 (按一下即可檢視大小完整的映射)
XML 網站地圖檔案會將網站的結構定義為階層。 這個階層式關聯性會透過元素的 <siteMapNode>
進階,在 XML 檔案中建立模型。 Web.sitemap
必須從 <siteMap>
具有精確一個 <siteMapNode>
子系的父節點開始。 這個最上層 <siteMapNode>
元素代表階層的根目錄,而且可能會有任意數目的子代節點。 每個 <siteMapNode>
元素都必須包含屬性,而且可以選擇性地包含 url
和 description
屬性;每個非空白 url
屬性都必須是唯一 title
的。
在 檔案中 Web.sitemap
輸入下列 XML:
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~/Default.aspx" title="Home">
<siteMapNode title="Membership">
<siteMapNode url="~/Membership/CreatingUserAccounts.aspx" title="Creating User Accounts" />
<siteMapNode url="~/Membership/UserBasedAuthorization.aspx" title="User-Based Authorization" />
<siteMapNode url="~/Membership/Guestbook.aspx" title="Storing Additional User Information" />
</siteMapNode>
</siteMapNode>
</siteMap>
上述網站地圖示記會定義圖 3 所示的階層。
圖 3:網站地圖代表階層式導覽結構, (按一下即可檢視大小完整的影像)
步驟 3:更新主版頁面以包含導覽使用者介面
ASP.NET 包含一些用於設計使用者介面的導覽相關 Web 控制項。 其中包括 Menu、TreeView 和 SiteMapPath 控制項。 Menu 和 TreeView 控制項分別呈現功能表或樹狀結構中的網站地圖結構,而 SiteMapPath 則會分別顯示流覽的目前節點及其上階。 網站地圖資料可以使用 SiteMapDataSource 系結至其他資料 Web 控制項,並可透過 SiteMap
類別以程式設計方式存取。
由於網站地圖架構和導覽控制項的徹底討論超出本教學課程系列的範圍,而不是花時間製作自己的導覽使用者介面,而是借用在 2.0 教學課程系列中使用資料 ASP.NET 2.0 教學課程系列中使用的連結,這會使用 Repeater 控制項來顯示兩深度的導覽連結清單。 如圖 4 所示。
在左側資料行中新增Two-Level連結清單
若要建立此介面,請將下列宣告式標記新增至 Site.master
主版頁面的左側資料行,其中文字 「TODO: Menu 將移至這裡...目前位於 。
<ul>
<li>
<asp:HyperLink runat="server" ID="lnkHome" NavigateUrl="~/Default.aspx">Home</asp:HyperLink>
</li>
<asp:Repeater runat="server" ID="menu" DataSourceID="SiteMapDataSource1">
<ItemTemplate>
<li>
<asp:HyperLink ID="lnkMenuItem" runat="server"
NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>
<asp:Repeater ID="submenu" runat="server" DataSource="<%#
((SiteMapNode) Container.DataItem).ChildNodes %>">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:HyperLink ID="lnkMenuItem" runat="server" NavigateUrl='<%#
Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="false" />
上述標記會將名為 menu
的 Repeater 控制項系結至 SiteMapDataSource,這會傳回 中所 Web.sitemap
定義的網站地圖階層。 由於 SiteMapDataSource 控制項的ShowStartingNode
屬性設定為 False,因此會從 「Home」 節點的子代開始傳回網站地圖的階層。 重複程式會顯示每個節點, (目前只是元素中的 <li>
「成員資格」) 。 另一個內部 Repeater 接著會在巢狀未排序清單中顯示目前節點的子系。
圖 4 顯示上述標記的轉譯輸出,其中包含我們在步驟 2 中建立的網站地圖結構。 Repeater 會轉譯 vanilla unordered 清單標記;中所 Styles.css
定義的級聯樣式表單規則負責美觀的版面配置。 如需上述標記運作方式的更詳細描述,請參閱 主版頁面和網站導覽 教學課程。
圖 4:流覽使用者介面會使用巢狀未排序清單轉譯, (按一下即可檢視完整大小的影像)
新增階層連結導覽
除了左側資料行中的連結清單之外,讓我們也讓每個頁面顯示 階層連結。 階層連結是導覽使用者介面元素,可快速顯示使用者其月臺階層中目前的位置。 SiteMapPath 控制項會使用網站地圖架構來判斷網站地圖中目前頁面的位置,然後根據這項資訊顯示階層連結。
具體而言,將 元素新增 <span>
至主版頁面的標頭 <div>
元素,並將新 <span>
元素的 class
屬性設定為 「breadcrumb」。 (類別 Styles.css
包含 「breadcrumb」 類別的規則。) Next,將 SiteMapPath 新增至這個新 <span>
元素。
<div id="header">
<span class="title">User Account Tutorials</span><br />
<span class="breadcrumb">
<asp:SiteMapPath ID="SiteMapPath1" runat="server">
</asp:SiteMapPath>
</span>
</div>
圖 5 顯示造訪 ~/Membership/CreatingUserAccounts.aspx
時 SiteMapPath 的輸出。
圖 5:階層連結在網站地圖中顯示目前頁面及其上階 (按一下即可檢視完整大小的影像)
步驟 4:移除自訂主體和身分識別邏輯
自訂主體和身分識別物件可以與已驗證的使用者相關聯。 我們藉由在 中 Global.asax
為應用程式 PostAuthenticateRequest
事件建立事件處理常式來完成此動作,此事件處理常式會在 驗證使用者之後 FormsAuthenticationModule
引發。 在此事件處理常式中,我們會將 所 FormsAuthenticationModule
新增的 和 FormsIdentity
物件取代 GenericPrincipal
為我們在該教學課程中建立的 CustomPrincipal
和 CustomIdentity
物件。
雖然自訂主體和身分識別物件在某些案例中很有用,但在大多數情況下, GenericPrincipal
和 FormsIdentity
物件就已足夠。 因此,我認為值得回到預設行為。 藉由移除或批註 PostAuthenticateRequest
事件處理常式或完全刪除 Global.asax
檔案來進行這項變更。
步驟 5:以程式設計方式建立新使用者
若要透過 Membership 架構建立新的使用者帳戶,請使用 Membership
類別的CreateUser
方法。 這個方法具有使用者名稱、密碼和其他使用者相關欄位的輸入參數。 在叫用時,它會將新使用者帳戶的建立委派給已設定的成員資格提供者,然後傳回MembershipUser
代表剛建立之使用者帳戶的物件。
方法 CreateUser
有四個多載,每個多載都接受不同的輸入參數數目:
CreateUser(username, password)
CreateUser(username, password, email)
CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, MembershipCreateStatus)
CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, MembershipCreateStatus)
這四個多載會因所收集的資訊量而有所不同。 例如,第一個多載只需要新使用者帳戶的使用者名稱和密碼,而第二個多載也需要使用者的電子郵件地址。
這些多載存在,因為建立新使用者帳戶所需的資訊取決於成員資格提供者的組態設定。 在 SQL Server 中建立成員資格架構教學課程中,我們檢查了 在 中 Web.config
指定成員資格提供者組態設定。 表 2 包含組態設定的完整清單。
影響可能使用多載的 CreateUser
其中一個這類成員資格提供者組態設定是 requiresQuestionAndAnswer
設定。 如果 requiresQuestionAndAnswer
設定為 true
(預設) ,則在建立新的使用者帳戶時,我們必須指定安全性問題和答案。 如果使用者需要重設或變更其密碼,稍後會使用此資訊。 具體而言,此時會顯示安全性問題,而且必須輸入正確的答案,才能重設或變更其密碼。 因此,如果 requiresQuestionAndAnswer
設定為 true
,則呼叫前兩 CreateUser
個多載其中一個會導致例外狀況,因為缺少安全性問題和答案。 由於我們的應用程式目前已設定為需要安全性問題和解答,因此我們必須在以程式設計方式建立使用者時,使用後者兩個多載的其中一個。
為了說明如何使用 CreateUser
方法,讓我們建立使用者介面,並在其中提示使用者輸入其名稱、密碼、電子郵件,以及預先定義安全性問題的解答。 CreatingUserAccounts.aspx
開啟 資料夾中的頁面 Membership
,並將下列 Web 控制項新增至內容控制項:
- 名為 的 TextBox
Username
- 名為
Password
的 TextBox,其TextMode
屬性設定為Password
- 名為 的 TextBox
Email
- 已清除其
Text
屬性的卷SecurityQuestion
標 - 名為 的 TextBox
SecurityAnswer
- 名為
CreateAccountButton
的按鈕,其 Text 屬性設定為 「建立使用者帳戶」 - 已清除其
Text
屬性的卷CreateAccountResults
標控制項
此時,您的畫面看起來應該類似圖 6 中顯示的螢幕擷取畫面。
圖 6:將各種 Web 控制項新增至 CreatingUserAccounts.aspx
頁面 (按一下即可檢視完整大小的影像)
SecurityQuestion
Label 和 SecurityAnswer
TextBox 旨在顯示預先定義的安全性問題,並收集使用者的答案。 請注意,安全性問題和答案都是以使用者為基礎儲存,因此可以讓每個使用者定義自己的安全性問題。 不過,在此範例中,我決定使用通用安全性問題,也就是:「您最愛的色彩為何?」
若要實作這個預先定義的安全性問題,請將常數新增至頁面的程式碼後置類別,並 passwordQuestion
為其指派安全性問題。 然後,在事件處理常式中 Page_Load
,將這個常數指派給 SecurityQuestion
Label 的 Text
屬性:
const string passwordQuestion = "What is your favorite color";
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
SecurityQuestion.Text = passwordQuestion;
}
接下來,建立 事件的 Click
事件處理常式 CreateAccountButton
,並新增下列程式碼:
protected void CreateAccountButton_Click(object sender, EventArgs e)
{
MembershipCreateStatus createStatus;
MembershipUser newUser = Membership.CreateUser(Username.Text, Password.Text, Email.Text, passwordQuestion, SecurityAnswer.Text, true, out createStatus);
switch (createStatus)
{
case MembershipCreateStatus.Success:
CreateAccountResults.Text = "The user account was successfully created!";
break;
case MembershipCreateStatus.DuplicateUserName:
CreateAccountResults.Text = "There already exists a user with this username.";
break;
case MembershipCreateStatus.DuplicateEmail:
CreateAccountResults.Text = "There already exists a user with this email address.";
break;
case MembershipCreateStatus.InvalidEmail:
CreateAccountResults.Text = "There email address you provided in invalid.";
break;
case MembershipCreateStatus.InvalidAnswer:
CreateAccountResults.Text = "There security answer was invalid.";
break;
case MembershipCreateStatus.InvalidPassword:
CreateAccountResults.Text = "The password you provided is invalid. It must be seven characters long and have at least one non-alphanumeric character.";
break;
default:
CreateAccountResults.Text = "There was an unknown error; the user account was NOT created.";
break;
}
}
Click
事件處理常式一開始會定義名為 createStatus
MembershipCreateStatus
類型的變數。 MembershipCreateStatus
是表示作業狀態的 CreateUser
列舉。 例如,如果成功建立使用者帳戶,則產生的 MembershipCreateStatus
實例會設定為 的值 Success
;另一方面,如果作業失敗,因為已有具有相同使用者名稱的使用者存在,則會將其設定為 的值 DuplicateUserName
。 在我們使用的多載中 CreateUser
,我們需要將 實例傳遞 MembershipCreateStatus
至 方法做為 out
參數。 此參數設定為 方法內 CreateUser
的適當值,我們可以在方法呼叫之後檢查其值,以判斷是否已成功建立使用者帳戶。
在呼叫 CreateUser
之後,傳入 createStatus
時, switch
語句會根據指派給 createStatus
的值來輸出適當的訊息。 圖 7 顯示成功建立新使用者時的輸出。 圖 8 和 9 顯示未建立使用者帳戶時的輸出。 在圖 8 中,訪客輸入五個字母的密碼,不符合成員資格提供者組態設定中拼出的密碼強度需求。 在圖 9 中,訪客嘗試使用現有的使用者名稱來建立使用者帳戶, (圖 7 中建立的使用者名稱) 。
圖 7:已成功建立新的使用者帳戶 (按一下即可檢視完整大小的映射)
圖 8:未建立使用者帳戶,因為提供的密碼太弱, (按一下即可檢視完整大小的映射)
圖 9:未建立使用者帳戶,因為使用者名稱已在使用中 (按一下即可檢視完整大小的影像)
注意
您可能想知道在使用前兩 CreateUser
個方法多載的其中一個時,如何判斷成功或失敗,這兩者都沒有類型的 MembershipCreateStatus
參數。 這兩個多載會在發生失敗時擲回MembershipCreateUserException
例外狀況,其中包含StatusCode
類型的 MembershipCreateStatus
屬性。
建立一些使用者帳戶之後,請列出 資料庫中 的 和 aspnet_Membership
資料表 SecurityTutorials.mdf
內容 aspnet_Users
,確認已建立帳戶。 如圖 10 所示,我已透過 CreatingUserAccounts.aspx
頁面新增兩個使用者:Tito 和 Bruce。
圖 10:成員資格使用者存放區中有兩位使用者:Tito 和 Bruce (按一下即可檢視完整大小的影像)
雖然成員資格使用者存放區現在包含 Bruce 和 Tito 的帳戶資訊,但我們尚未實作可讓 Bruce 或 Tito 登入網站的功能。 目前, Login.aspx
會針對一組硬式編碼的使用者名稱/密碼組來驗證使用者的認證, 它 不會 針對成員資格架構驗證提供的認證。 現在,在 和 aspnet_Membership
資料表中看到 aspnet_Users
新的使用者帳戶必須足夠。 在下一個教學課程中,針對成員資格使用者存放區驗證使用者認證,我們將更新登入頁面,以針對成員資格存放區進行驗證。
注意
如果您沒有在資料庫中看到任何使用者 SecurityTutorials.mdf
,可能是因為您的 Web 應用程式使用預設成員資格提供者 , AspNetSqlMembershipProvider
它會使用 ASPNETDB.mdf
資料庫作為其使用者存放區。 若要判斷這是問題,請按一下方案總管中的 [重新整理] 按鈕。 如果名為 ASPNETDB.mdf
的資料庫已新增至 App_Data
資料夾,這就是問題。 如需如何正確設定成員資格提供者的指示,請回到在SQL Server 教學課程中建立成員資格架構的步驟 4 。
在大部分的建立使用者帳戶案例中,訪客會看到一些介面來輸入其使用者名稱、密碼、電子郵件和其他基本資訊,此時會建立新的帳戶。 在此步驟中,我們查看手動建置這類介面,然後瞭解如何使用 Membership.CreateUser
方法來根據使用者的輸入,以程式設計方式新增新的使用者帳戶。 不過,我們的程式碼剛建立新的使用者帳戶。 它未執行任何後續動作,例如在剛建立的使用者帳戶下登入網站,或傳送確認電子郵件給使用者。 這些額外的步驟需要 Button Click
事件處理常式中的其他程式碼。
ASP.NET 隨附 CreateUserWizard 控制項,其設計目的是要處理使用者帳戶建立程式,從轉譯用於建立新使用者帳戶的使用者介面,到在成員資格架構中建立帳戶,以及執行帳戶後建立工作,例如傳送確認電子郵件,並將剛建立的使用者記錄到網站。 使用 CreateUserWizard 控制項就像將 CreateUserWizard 控制項從 [工具箱] 拖曳到頁面一樣簡單,然後設定幾個屬性。 在大部分情況下,您不需要撰寫單行程式碼。 我們將在步驟 6 中詳細探索此 nifty 控制項。
如果只有透過一般建立帳戶網頁建立新的使用者帳戶,您不太可能需要撰寫使用 CreateUser
方法的程式碼,因為 CreateUserWizard 控制項可能會符合您的需求。 不過,當您需要高度自訂的建立帳戶使用者體驗,或需要透過替代介面以程式設計方式建立新的使用者帳戶時,此方法 CreateUser
就很有用。 例如,您可能有一個頁面可讓使用者上傳包含來自其他應用程式之使用者資訊的 XML 檔案。 頁面可能會剖析已上傳 XML 檔案的內容,並藉由呼叫 CreateUser
方法,為 XML 中代表的每個使用者建立新的帳戶。
步驟 6:使用 CreateUserWizard 控制項建立新使用者
ASP.NET 隨附許多登入 Web 控制項。 這些控制項可協助許多常見的使用者帳戶和登入相關案例。 CreateUserWizard 控制項是一個這類控制項,其設計目的是要呈現使用者介面,以便將新的使用者帳戶新增至成員資格架構。
就像其他許多登入相關的 Web 控制項一樣,CreateUserWizard 不需要撰寫單行程式碼即可使用。 它會根據成員資格提供者的組態設定,以直覺方式提供使用者介面,並在使用者輸入必要資訊之後,于內部呼叫 Membership
類別 CreateUser
的 方法,然後按一下 [建立使用者] 按鈕。 CreateUserWizard 控制項非常可自訂。 帳戶建立程式的各個階段都會引發一些事件。 我們可以視需要建立事件處理常式,將自訂邏輯插入帳戶建立工作流程。 此外,CreateUserWizard 的外觀非常有彈性。 有數個屬性可定義預設介面的外觀;如有必要,可以將控制項轉換成範本,或新增額外的使用者註冊「步驟」。
讓我們從使用 CreateUserWizard 控制項的預設介面和行為開始。 接著,我們將探索如何透過控制項的屬性和事件自訂外觀。
檢查 CreateUserWizard 的預設介面和行為
返回資料夾中的頁面 Membership
,切換至 CreatingUserAccounts.aspx
[設計] 或 [分割] 模式,然後將 CreateUserWizard 控制項新增至頁面頂端。 CreateUserWizard 控制項會列在 [工具箱的登入控制項] 區段下。 新增控制項之後,將其 ID
屬性設定為 RegisterUser
。 如圖 11 所示的螢幕擷取畫面,CreateUserWizard 會轉譯具有新使用者使用者名稱、密碼、電子郵件地址和安全性問題的答案文字方塊的介面。
圖 11:CreateUserWizard 控制項轉譯一般建立使用者介面 (按一下即可檢視大小完整的影像)
讓我們花點時間比較 CreateUserWizard 控制項所產生的預設使用者介面,以及我們在步驟 5 中建立的介面。 針對入門,CreateUserWizard 控制項可讓訪客同時指定安全性問題和答案,而手動建立的介面則使用預先定義的安全性問題。 CreateUserWizard 控制項的介面也包含驗證控制項,但我們尚未在介面的表單欄位上實作驗證。 而 CreateUserWizard 控制項介面包含 [確認密碼] 文字方塊 (以及 CompareValidator,以確保輸入 「Password」 和 [比較密碼] 文字方塊的文字相等) 。
有趣的是,CreateUserWizard 控制項會在轉譯其使用者介面時參考成員資格提供者的組態設定。 例如,只有在設定為 True 時 requiresQuestionAndAnswer
,才會顯示安全性問題和答案文字方塊。 同樣地,CreateUserWizard 會自動新增 RegularExpressionValidator 控制項,以確保符合密碼強度需求,並根據 、 和 組態設定來設定其 ErrorMessage
ValidationExpression
和 passwordStrengthRegularExpression
屬性 minRequiredPasswordLength
。 minRequiredNonalphanumericCharacters
CreateUserWizard 控制項如其名稱所示,衍生自 精靈控制項。 精靈控制項的設計目的是要提供用來完成多步驟工作的介面。 精靈控制項可能有任意數目的 WizardSteps
,每個控制項都是定義該步驟之 HTML 和 Web 控制項的範本。 精靈控制項一開始會顯示第一個 ,以及允許使用者從一 WizardStep
個步驟繼續進行的導覽控制項,或返回先前的步驟。
如圖 11 所示的宣告式標記,CreateUserWizard 控制項的預設介面包含兩個 WizardSteps:
CreateUserWizardStep
– 轉譯介面,以收集用來建立新使用者帳戶的資訊。 這是圖 11 所示的步驟。CompleteWizardStep
– 轉譯訊息,指出已成功建立帳戶。
CreateUserWizard 的外觀和行為可以藉由將其中一個步驟轉換成範本,或新增您自己的 WizardSteps
來修改。 我們將在儲存其他使用者資訊教學課程中,查看將 新增 WizardStep
至註冊介面。
讓我們看看 CreateUserWizard 控制項的運作情形。 CreatingUserAccounts.aspx
透過瀏覽器流覽頁面。 首先,在 CreateUserWizard 的介面中輸入一些不正確值。 請嘗試輸入不符合密碼強度需求的密碼,或將 [使用者名稱] 文字方塊保留空白。 CreateUserWizard 會顯示適當的錯誤訊息。 圖 12 顯示嘗試建立具有不足強式密碼的使用者時的輸出。
圖 12:CreateUserWizard 自動插入驗證控制項 (按一下即可檢視大小完整的映射)
接下來,在 CreateUserWizard 中輸入適當的值,然後按一下 [建立使用者] 按鈕。 假設輸入必要的欄位且密碼強度已足夠,CreateUserWizard 會透過成員資格架構建立新的使用者帳戶,然後顯示 CompleteWizardStep
的介面 (請參閱圖 13) 。 在幕後,CreateUserWizard 會呼叫 Membership.CreateUser
方法,就像我們在步驟 5 中所做的一樣。
圖 13:已成功建立新的使用者帳戶 (按一下即可檢視大小完整的映射)
注意
如圖 13 所示, CompleteWizardStep
的 介面包含 [繼續] 按鈕。 不過,此時按一下它只會執行回傳,讓訪客留在相同的頁面上。 在 [透過其屬性自訂 CreateUserWizard 的外觀和行為] 區段中,我們將探討如何讓此按鈕將訪客傳送至 Default.aspx
(或其他頁面) 。
建立新的使用者帳戶之後,返回 Visual Studio 並檢查 aspnet_Users
aspnet_Membership
和資料表,就像我們在圖 10 中所做的一樣,確認已成功建立帳戶。
透過其屬性自訂 CreateUserWizard 的行為和外觀
CreateUserWizard 可以透過屬性、 WizardSteps
和事件處理常式,以各種方式自訂。 在本節中,我們將探討如何透過其屬性自訂控制項的外觀;下一節將探討透過事件處理常式擴充控制項的行為。
幾乎所有顯示在 CreateUserWizard 控制項預設使用者介面中的文字都可以透過其大量屬性來自訂。 例如,文字方塊左側顯示的 [使用者名稱]、[密碼]、[確認密碼]、[電子郵件]、[安全性問題] 和 [安全性答案] 標籤可以分別由 UserNameLabelText
、 ConfirmPasswordLabelText
PasswordLabelText
、、 EmailLabelText
、 QuestionLabelText
和 AnswerLabelText
屬性自訂。 同樣地,還有屬性可用來指定 和 CompleteWizardStep
中 CreateUserWizardStep
「建立使用者」和「繼續」按鈕的文字,以及這些按鈕是否轉譯為 Buttons、LinkButtons 或 ImageButtons。
色彩、框線、字型和其他視覺化元素可透過樣式屬性的主機進行設定。 CreateUserWizard 控制項本身具有常見的 Web 控制項樣式屬性 – BackColor
、 BorderStyle
、 CssClass
、 Font
等等 ,而且有一些樣式屬性可用來定義 CreateUserWizard 介面特定區段的外觀。 例如,屬性 TextBoxStyle
會定義 中的 CreateUserWizardStep
文字方塊樣式,而TitleTextStyle
屬性會定義標題的樣式 (「註冊新帳戶」) 。
除了外觀相關屬性之外,還有一些會影響 CreateUserWizard 控制項行為的屬性。 DisplayCancelButton
如果設定為 True,則會顯示 [建立使用者] 按鈕旁的 [取消] 按鈕, (預設值為 False) 。 如果您顯示 [取消] 按鈕,請務必也設定CancelDestinationPageUrl
屬性,以指定使用者在按一下 [取消] 之後傳送到的頁面。 如上一節所述,介面中的 CompleteWizardStep
[繼續] 按鈕會造成回傳,但讓訪客位於相同的頁面上。 若要在按一下 [繼續] 按鈕之後將訪客傳送至其他頁面,只要在ContinueDestinationPageUrl
屬性中指定 URL 即可。
讓我們更新 RegisterUser
CreateUserWizard 控制項以顯示 [取消] 按鈕,並在按一下 [取消] 或 [繼續] 按鈕時將訪客傳送至 Default.aspx
。 若要完成這項作業,請將 DisplayCancelButton
屬性設定為 True,並將 CancelDestinationPageUrl
和 ContinueDestinationPageUrl
屬性設定為 「~/Default.aspx」。 圖 14 顯示透過瀏覽器檢視時更新的 CreateUserWizard。
圖 14:包含 CreateUserWizardStep
[取消] 按鈕 (按一下即可檢視大小完整的影像)
當訪客輸入使用者名稱、密碼、電子郵件地址和安全性問題及解答,然後按一下 [建立使用者],就會建立新的使用者帳戶,且訪客會以新建立的使用者身分登入。 假設流覽頁面的人員自行建立新的帳戶,這可能是所需的行為。 不過,您可能想要允許系統管理員新增使用者帳戶。 如此一來,將會建立使用者帳戶,但系統管理員會以系統管理員 (身分登入,而不是新建立的帳戶) 。 這個行為可以透過布林LoginCreatedUser
值屬性修改。
成員資格架構中的使用者帳戶包含已核准的旗標;未核准的使用者無法登入網站。 根據預設,新建立的帳戶會標示為已核准,讓使用者立即登入網站。 不過,可以讓新的使用者帳戶標示為未核准。 或許您想要系統管理員手動核准新使用者,才能登入;或者,您可能想要先確認在註冊時輸入的電子郵件地址有效,再允許使用者登入。 不論情況為何,您可以將 CreateUserWizard 控制項的 DisableCreatedUser
屬性設定為 True, (預設值為 False) ,讓新建立的使用者帳戶標示為未核准。
附注的其他行為相關屬性包括 AutoGeneratePassword
和 MailDefinition
。 AutoGeneratePassword
如果屬性設定為 True,則 CreateUserWizardStep
不會顯示 [密碼] 和 [確認密碼] 文字方塊;而是使用 Membership
類別GeneratePassword
的 方法自動產生新建立的使用者密碼。 方法 GeneratePassword
會建構長度為指定長度的密碼,且具有足夠數目的非英數位元,以滿足設定的密碼強度需求。
如果您想要將電子郵件傳送至帳戶建立程式期間所指定的電子郵件地址,此屬性 MailDefinition
會很有用。 屬性 MailDefinition
包含一系列的子屬性,用來定義建構的電子郵件訊息相關資訊。 這些子屬性包含 、 Priority
、 IsBodyHtml
、 From
、、 CC
和 BodyFileName
等 Subject
選項。 屬性 BodyFileName
指向包含電子郵件訊息本文的文字或 HTML 檔案。 本文支援兩個預先定義的預留位置: <%UserName%>
和 <%Password%>
。 如果存在於檔案中 BodyFileName
,這些預留位置將會取代為剛建立的使用者名稱和密碼。
注意
控制項 CreateUserWizard
的 MailDefinition
屬性只會指定建立新帳戶時所傳送之電子郵件訊息的詳細資料。 它不包含電子郵件訊息實際 (傳送方式的任何詳細資料,也就是使用 SMTP 伺服器或郵件卸載目錄、任何驗證資訊等等) 。 這些低階詳細資料必須在 中的 <system.net>
Web.config
區段中定義。 如需這些組態設定的詳細資訊,以及一般從 ASP.NET 2.0 傳送電子郵件的詳細資訊,請參閱SystemNetMail.com和我的文章:在 ASP.NET 2.0 中傳送Email。
使用事件處理常式擴充 CreateUserWizard 的行為
CreateUserWizard 控制項在其工作流程期間引發一些事件。 例如,在訪客輸入其使用者名稱、密碼和其他相關資訊,然後按一下 [建立使用者] 按鈕之後,CreateUserWizard 控制項會引發其CreatingUser
事件。 如果在建立程式期間發生問題,就會CreateUserError
引發事件;不過,如果成功建立使用者,則會CreatedUser
引發事件。 還有其他 CreateUserWizard 控制項事件會引發,但這些事件是三個最德文的控制項事件。
在某些情況下,我們可能會想要點選 CreateUserWizard 工作流程,我們可以藉由為適當的事件建立事件處理常式來執行此動作。 為了說明這一點,讓我們增強 RegisterUser
CreateUserWizard 控制項,以在使用者名稱和密碼中包含一些自訂驗證。 特別是,讓我們增強 CreateUserWizard,讓使用者名稱不能包含開頭或尾端空格,而且使用者名稱不能出現在密碼中的任何位置。 簡言之,我們想要防止某人建立使用者名稱,例如 「Scott」,或具有像是 「Scott」 和 「Scott.1234」 的使用者名稱/密碼組合。
為了達成此目的,我們將為 CreatingUser
事件建立事件處理常式,以執行額外的驗證檢查。 如果提供的資料無效,我們需要取消建立程式。 我們也必須將標籤 Web 控制項新增至頁面,以顯示說明使用者名稱或密碼不正確訊息。 從在 CreateUserWizard 控制項底下新增 Label 控制項開始,將其 屬性設定為 ,並將其 ID
ForeColor
屬性設定為 Red
。 InvalidUserNameOrPasswordMessage
清除其 Text
屬性,並將其 和 Visible
屬性設定 EnableViewState
為 False。
<asp:Label runat="server" id="InvalidUserNameOrPasswordMessage"
Visible="false" ForeColor="Red" EnableViewState="false">
</asp:Label>
接下來,建立 CreateUserWizard 控制項事件的 CreatingUser
事件處理常式。 若要建立事件處理常式,請選取Designer中的控制項,然後移至屬性視窗。 從該處按一下閃電圖示,然後按兩下適當的事件來建立事件處理常式。
將下列程式碼加入至 CreatingUser
事件處理常式:
protected void RegisterUser_CreatingUser(object sender, LoginCancelEventArgs e)
{
string trimmedUserName = RegisterUser.UserName.Trim();
if (RegisterUser.UserName.Length != trimmedUserName.Length)
{
// Show the error message
InvalidUserNameOrPasswordMessage.Text = "The username cannot contain leading or trailing spaces.";
InvalidUserNameOrPasswordMessage.Visible = true;
// Cancel the create user workflow
e.Cancel = true;
}
else
{
// Username is valid, make sure that the password does not contain the username
if (RegisterUser.Password.IndexOf(RegisterUser.UserName, StringComparison.OrdinalIgnoreCase) >= 0)
{
// Show the error message
InvalidUserNameOrPasswordMessage.Text = "The username may not appear anywhere in the password.";
InvalidUserNameOrPasswordMessage.Visible = true;
// Cancel the create user workflow
e.Cancel = true;
}
}
}
請注意,輸入 CreateUserWizard 控制項的使用者名稱和密碼可透過其 UserName
和Password
屬性分別取得。 我們會在上述事件處理常式中使用這些屬性來判斷提供的使用者名稱是否包含前置或尾端空格,以及使用者名稱是否在密碼內找到。 如果符合上述任一條件,則會在 Label 中 InvalidUserNameOrPasswordMessage
顯示錯誤訊息,而事件處理常式的 e.Cancel
屬性會設定為 true
。 如果 e.Cancel
設定為 true
,CreateUserWizard 會縮短其工作流程,有效地取消使用者帳戶建立程式。
圖 15 顯示當使用者輸入具有前置空格的使用者名稱時的螢幕擷取畫面 CreatingUserAccounts.aspx
。
圖 15:不允許使用前置或尾端空格的使用者名稱, (按一下即可檢視完整大小的影像)
注意
我們將會在儲存其他使用者資訊教學課程中看到 使用 CreateUserWizard 控制項 CreatedUser
事件的範例。
摘要
類別 Membership
的 CreateUser
方法會在成員資格架構中建立新的使用者帳戶。 其方式是將呼叫委派給已設定的成員資格提供者。 在 的 SqlMembershipProvider
案例中 CreateUser
,方法會將記錄新增至 aspnet_Users
和 aspnet_Membership
資料庫資料表。
雖然新的使用者帳戶可以程式設計方式建立 (,如我們在步驟 5) 中所見,但使用 CreateUserWizard 控制項的速度更快且更簡單的方法。 此控制項會轉譯多步驟使用者介面,以收集使用者資訊,並在 Membership 架構中建立新的使用者。 實際上,此控制項會使用與步驟 5 中檢查相同的 Membership.CreateUser
方法,但控制項會建立使用者介面、驗證控制項,並回應使用者帳戶建立錯誤,而不需要撰寫程式碼。
此時,我們已具備建立新使用者帳戶的功能。 不過,登入頁面仍會針對我們在第二個教學課程中回指定的硬式編碼認證進行驗證。 在下一個教學 課程中,我們將更新 Login.aspx
,以根據成員資格架構驗證使用者提供的認證。
快樂的程式設計!
深入閱讀
如需本教學課程中所討論之主題的詳細資訊,請參閱下列資源:
CreateUser
技術檔- CreateUserWizard 控制項概觀
- System-Based網站地圖提供者建立檔案
- 使用 ASP.NET 2.0 精靈控制項建立逐步使用者介面
- 檢查 ASP.NET 2.0 的網站導覽
- 主版頁面和網站導覽
- 您正在等候的 SQL 網站地圖提供者
關於作者
Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,以及 4GuysFromRolla.com 的建立者,自 1998 年起就與 Microsoft Web 技術合作。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 Scott 可以透過 mitchell@4guysfromrolla.com 在 上的部落格或透過 http://ScottOnWriting.NET 其部落格來連線。
特別感謝...
本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Teresa Murphy。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com 。