建立使用者帳戶 (C#)
注意
自本文撰寫以來,ASP.NET 成員資格提供者已由 ASP.NET Identity 取代。 我們強烈建議更新應用程式以使用 ASP.NET Identity 平台,而不是撰寫本文時介紹的成員資格提供者。 與 ASP.NET 成員資格系統相比,ASP.NET Identity 具有許多優勢,包括:
- 更好的效能
- 改進的可擴展性和可測試性
- 支援 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
和將元素的mode
屬性設定<authentication>
為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
宣告式標記。 這麼做之後,五頁的標記中每個都應該只包含一個 Content 控件。
步驟 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
。
由於網站地圖架構和導覽控件的徹底討論已超出本教學課程系列的範圍,而不是花時間製作我們自己的導覽使用者介面,而是借用我在 ASP.NET 2.0 教學課程系列中使用數據一個,該系列使用 Repeater 控件來顯示兩深的導覽連結清單, 如圖 4 所示。
在左側數據行中新增兩層連結清單
若要建立此介面,請將下列宣告式標記新增至 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 list markup;中 Styles.css
定義的級聯樣式表單規則負責美觀的版面配置。 如需上述標記運作方式的更詳細描述,請參閱 主版頁面和網站導覽 教學課程。
圖 4:使用巢狀未排序列表轉譯導覽使用者介面(按兩下以檢視完整大小的影像)
新增階層連結流覽
除了左側數據行中的連結清單之外,我們也會讓每個頁面顯示 階層連結。 階層連結是瀏覽使用者介面元素,可快速向用戶顯示其站台階層中目前的位置。 SiteMapPath 控件會使用網站地圖架構來判斷網站地圖中目前頁面的位置,然後根據此資訊顯示階層連結。
具體來說,將元素新增 <span>
至主版頁面的標頭 <div>
元素,並將新 <span>
元素的 class
屬性設定為 “breadcrumb”。 (類別 Styles.css
包含 “breadcrumb” 類別的規則。接下來,將 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:移除自定義主體和身分識別邏輯
自訂主體和身分識別物件可以與已驗證的使用者相關聯。 我們藉由為應用程式的 PostAuthenticateRequest
事件建立 事件處理程式Global.asax
來完成這項作業,在驗證用戶之後FormsAuthenticationModule
引發。 在此事件處理程式中,我們將 所新增FormsAuthenticationModule
的 和 FormsIdentity
物件取代GenericPrincipal
為我們在該教學課程中建立的 CustomPrincipal
和 CustomIdentity
物件。
雖然自定義主體和身分識別物件在某些案例中很有用,但在大多數情況下 GenericPrincipal
,和 FormsIdentity
物件就已足夠。 因此,我認為回到默認行為是值得的。 藉由移除或批注 PostAuthenticateRequest
事件處理程式或完全刪除 Global.asax
檔案,來進行這項變更。
步驟 5:以程序設計方式建立新使用者
若要透過成員資格架構建立新的用戶帳戶,請使用 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
頁面 (按兩下以檢視完整大小的影像)
Label SecurityQuestion
和 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;
}
接下來,建立 CreateAccountButton
Click
事件的事件處理程式,並新增下列程序代碼:
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 中詳細探索此巧妙的控件。
如果只有透過一般建立帳戶網頁建立新的用戶帳戶,您就不太可能需要撰寫使用 CreateUser
方法的程式代碼,因為 CreateUserWizard 控制項可能會符合您的需求。 不過,當您需要高度自定義的建立帳戶用戶體驗,或需要透過替代介面以程序設計方式建立新的用戶帳戶時, CreateUser
此方法就很方便。 例如,您可能有一個頁面,可讓使用者上傳包含來自其他應用程式之使用者資訊的 XML 檔案。 頁面可能會剖析上傳的 XML 檔案內容,並藉由呼叫 CreateUser
方法,為 XML 中代表的每個使用者建立新的帳戶。
步驟 6:使用 CreateUserWizard 控件建立新使用者
ASP.NET 隨附許多登入 Web 控制件。 這些控件可協助許多常見的用戶帳戶和登入相關案例。 CreateUserWizard 控件是一個這類控件,其設計目的是要呈現將新用戶帳戶新增至 Membership 架構的用戶介面。
如同其他許多與 Login 相關的 Web 控制件,CreateUserWizard 不需要撰寫單行程式代碼即可使用。 它會根據成員資格提供者的組態設定提供使用者介面,並在使用者輸入必要資訊后,於內部呼叫 Membership
類別 CreateUser
的方法,然後按兩下 [建立使用者] 按鈕。 CreateUserWizard 控件非常可自定義。 帳戶建立程式的各個階段都會引發許多事件。 我們可以視需要建立事件處理程式,在帳戶建立工作流程中插入自定義邏輯。 此外,CreateUserWizard 的外觀非常靈活。 有一些屬性可定義預設介面的外觀;如有需要,可以將控件轉換成範本,也可以新增額外的用戶註冊「步驟」。
讓我們從使用 CreateUserWizard 控件的預設介面和行為開始。 然後,我們將探索如何透過控件的屬性和事件來自定義外觀。
檢查 CreateUserWizard 的預設介面和行為
CreatingUserAccounts.aspx
返回資料夾中的頁面Membership
,切換至 [設計] 或 [分割] 模式,然後將 CreateUserWizard 控件新增至頁面頂端。 CreateUserWizard 控制者會在 [工具箱的登入控件] 區段下提交。 新增 控制項之後,將其 ID
屬性設定為 RegisterUser
。 如圖 11 所示的螢幕快照,CreateUserWizard 會轉譯具有新使用者使用者名稱、密碼、電子郵件地址和安全性問題和解答文字框的介面。
圖 11:CreateUserWizard 控件轉譯一般建立使用者介面 (按兩下以檢視完整大小的影像)
讓我們花點時間比較 CreateUserWizard 控件所產生的預設使用者介面,以及我們在步驟 5 中建立的介面。 對於入門,CreateUserWizard 控件可讓訪客同時指定安全性問題和答案,而我們手動建立的介面則使用預先定義的安全性問題。 CreateUserWizard 控件的介面也包含驗證控件,但我們尚未在介面的表單域上實作驗證。 CreateUserWizard 控件介面包含 [確認密碼] 文本框(以及 CompareValidator,以確保輸入 “Password” 和 “Compare Password” 文本框的文字相等)。
有趣的是,CreateUserWizard 控件會在轉譯其使用者介面時參考成員資格提供者的組態設定。 例如,只有在 設定為 True 時 requiresQuestionAndAnswer
,才會顯示安全性問題和答案文本框。 同樣地,CreateUserWizard 會自動新增 RegularExpressionValidator 控件,以確保符合密碼強度需求,並根據 、 和 組態設定來設定其 ErrorMessage
和 ValidationExpression
passwordStrengthRegularExpression
屬性minRequiredPasswordLength
。 minRequiredNonalphanumericCharacters
CreateUserWizard 控件,如其名稱所示,衍生自 Wizard控件。 精靈控件的設計目的是提供完成多步驟工作的介面。 精靈控件可能有任意數目 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 的行為和外觀
您可以透過屬性、 WizardSteps
和事件處理程式,以各種方式自定義 CreateUserWizard。 在本節中,我們將探討如何透過控件的屬性來自定義控件的外觀;下一節將探討透過事件處理程式擴充控件的行為。
幾乎所有顯示在 CreateUserWizard 控件的預設使用者介面中的文字,都可以透過其大量的屬性來自定義。 例如,文本框左側顯示的 「用戶名稱」、「密碼」、「確認密碼」、「電子郵件」、「安全性問題」和「安全性答案」標籤,可以分別由UserNameLabelText
、PasswordLabelText
ConfirmPasswordLabelText
EmailLabelText
QuestionLabelText
和 AnswerLabelText
屬性自定義。 同樣地,還有屬性可指定 和 CompleteWizardStep
中 CreateUserWizardStep
[建立使用者] 和 [繼續] 按鈕的文字,以及這些按鈕是否轉譯為 Buttons、LinkButtons 或 ImageButtons。
色彩、框線、字型和其他視覺元素可透過許多樣式屬性來設定。 CreateUserWizard 控件本身具有常見的 Web 控件樣式屬性 – BackColor
、 BorderStyle
、 CssClass
、 Font
等等,而且有一些樣式屬性可定義 CreateUserWizard 介面特定區段的外觀。 例如,屬性TextBoxStyle
會定義 中CreateUserWizardStep
文本框的樣式,而 TitleTextStyle
屬性會定義標題的樣式(「註冊新帳戶」)。
除了外觀相關屬性之外,還有一些會影響 CreateUserWizard 控件行為的屬性。 如果設定為 True,則 DisplayCancelButton
屬性會顯示 [建立使用者] 按鈕旁的 [取消] 按鈕(預設值為 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 伺服器或郵件投遞目錄、任何驗證資訊等等)。 這些低階詳細數據必須在中的 Web.config
區段中定義<system.net>
。 如需這些組態設定的詳細資訊,以及一般從 ASP.NET 2.0 傳送電子郵件的詳細資訊,請參閱 SystemNetMail.com 和我的文章: ASP.NET 2.0 傳送電子郵件的常見問題。
使用事件處理程式擴充 CreateUserWizard 的行為
CreateUserWizard 控件在其工作流程期間會引發一些事件。 例如,在訪客輸入其使用者名稱、密碼和其他相關信息,然後按兩下 [建立使用者] 按鈕之後,CreateUserWizard 控件會引發其 CreatingUser
事件。 如果在建立程式期間發生問題, CreateUserError
就會引發事件 ;不過,如果成功建立使用者,則會 CreatedUser
引發事件 。 還有其他 CreateUserWizard 控件事件會引發,但這些事件是最德式的三個。
在某些情況下,我們可能會想要點選 CreateUserWizard 工作流程,我們可以藉由為適當的事件建立事件處理程式來執行此動作。 為了說明這一點,讓我們增強 RegisterUser
CreateUserWizard 控件,以在使用者名稱和密碼中包含一些自定義驗證。 特別是,讓我們增強 CreateUserWizard,讓使用者名稱不能包含前置或尾端空格,而且用戶名稱不能出現在密碼中的任何位置。 簡言之,我們想要防止有人建立用戶名稱,例如 “Scott”,或具有 “Scott” 和 “Scott.1234” 等用戶名稱/密碼組合。
為了達成此目的,我們將建立 CreatingUser
事件的事件處理程式,以執行額外的驗證檢查。 如果提供的數據無效,我們需要取消建立程式。 我們也必須將標籤 Web 控制項新增至頁面,以顯示說明使用者名稱或密碼無效的訊息。 從在 CreateUserWizard 控制項底下新增 Label 控制元件開始,將其 ID
屬性設定為 InvalidUserNameOrPasswordMessage
,並將其 ForeColor
屬性設定為 Red
。 清除其 Text
屬性,並將其 和 Visible
屬性設定EnableViewState
為 False。
<asp:Label runat="server" id="InvalidUserNameOrPasswordMessage"
Visible="false" ForeColor="Red" EnableViewState="false">
</asp:Label>
接下來,建立 CreateUserWizard 控件事件的 CreatingUser
事件處理程式。 若要建立事件處理程式,請選取設計工具中的控件,然後移至 屬性視窗。 從該處按兩下閃電圖示,然後按兩下適當的事件來建立事件處理程式。
將下列程式碼加入至 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
屬性分別取得。 我們會在上述事件處理程式中使用這些屬性來判斷提供的用戶名稱是否包含前置或尾端空格,以及用戶名稱是否在密碼內找到。 如果符合上述任一條件,則標籤中 InvalidUserNameOrPasswordMessage
會顯示錯誤訊息,而事件處理程式的 e.Cancel
屬性會設定為 true
。 如果 e.Cancel
設定為 true
,則 CreateUserWizard 會縮短其工作流程,有效地取消使用者帳戶建立程式。
圖 15 顯示當使用者輸入具有前置空格的用戶名稱時,的螢幕快照 CreatingUserAccounts.aspx
。
圖 15:不允許具有前置或尾端空格的使用者名稱(單擊以檢視完整大小的影像)
注意
我們將在儲存其他使用者資訊教學課程中看到使用 CreateUserWizard 控件事件的CreatedUser
範例。
摘要
類別 Membership
的 CreateUser
方法會在 Membership 架構中建立新的用戶帳戶。 其方式是將呼叫委派給已設定的成員資格提供者。 在的案例中 SqlMembershipProvider
, CreateUser
方法會將記錄新增至 aspnet_Users
和 aspnet_Membership
資料庫數據表。
雖然可以程序設計方式建立新的用戶帳戶(如我們在步驟 5 中所見),但使用 CreateUserWizard 控制件的更快且更簡單的方法。 此控件會轉譯多步驟使用者介面,以收集用戶資訊,並在成員資格架構中建立新的使用者。 實際上,此控件會使用與步驟 5 中檢查相同的 Membership.CreateUser
方法,但控件會建立使用者介面、驗證控件,並回應用戶帳戶建立錯誤,而不需要撰寫程式代碼。
此時,我們已有建立新用戶帳戶的功能。 不過,登入頁面仍會針對我們在第二個教學課程中指定的硬式編碼認證進行驗證。 在下一個教學課程中,我們將更新Login.aspx
,以針對成員資格架構驗證使用者提供的認證。
快樂程式!
深入閱讀
有關本教學課程中討論的主題的更多資訊,請參閱以下資源:
CreateUser
技術檔- CreateUserWizard 控件概觀
- 建立文件系統網站對應提供者
- 使用 ASP.NET 2.0 精靈控件建立逐步用戶介面
- 檢查 ASP.NET 2.0 的網站導覽
- 主版頁面和網站導覽
- 您一直在等候的 SQL 網站地圖提供者
關於作者
斯科特·米切爾,多個 ASP/ASP.NET 書籍的作者,4GuysFromRolla.com 的創始人,自1998年以來一直與Microsoft Web 技術合作。 Scott 擔任獨立顧問、講師和作家。 他的新書是 Sams Teach Yourself ASP.NET 2.0 in 24 Hours。 斯科特可以透過 mitchell@4guysfromrolla.com 他在的部落格聯繫到或通過他的博客 http://ScottOnWriting.NET。
特別感謝
本教學系列得到了許多有用的審閱者的審閱。 本教學的首席審閱者是 Teresa Murphy。 有興趣查看我即將發表的 MSDN 文章嗎? 如果是這樣,請留言給我 mitchell@4GuysFromRolla.com。