日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

Security Tutorials系列文章第五章:Creating U

系統(tǒng) 2228 0


Security Tutorials系列文章第五章:Creating User Accounts

本文英文原版及代碼下載:
http://www.asp.net/learn/security/tutorial-05-cs.aspx

導(dǎo)言:
在第四章,我們?cè)谝粋€(gè)數(shù)據(jù)庫(kù)里安裝了application services schema,它添加了對(duì)SqlMembershipProvider 和 SqlRoleProvider來(lái)說(shuō)必需的表、視圖、存儲(chǔ)過(guò)程.這為我們的后續(xù)文章打下了良好的基礎(chǔ).在本文,我們將使用Membership framework(通過(guò)SqlMembershipProvider)來(lái)創(chuàng)建新的用戶賬戶.我們將看到如何通過(guò)編程的方式以及利用ASP.NET內(nèi)置的CreateUserWizard控件來(lái)創(chuàng)建新用戶帳戶.

除了學(xué)習(xí)如何創(chuàng)建新用戶帳戶外,我們將對(duì)在前面文章里創(chuàng)建的演示站點(diǎn)進(jìn)行改動(dòng).使站點(diǎn)包含一個(gè)login page,以使users’ credentials生效,而不是采用硬編碼的username/password的形式來(lái)處理.此外,在Global.asax里包含了為通過(guò)認(rèn)證的用戶創(chuàng)建自定義IPrincipal 和 IIdentity對(duì)象的代碼.我們將對(duì)login page進(jìn)行更新,利用Membership framework來(lái)使users’ credentials生效,同時(shí)移除那些自定義的principal 和 identity邏輯.


Forms Authentication 和 Membership Checklist

在使用Membership framework之前,讓我們花點(diǎn)時(shí)間來(lái)回顧一下這一路走來(lái)所執(zhí)行的重要的步驟.在一個(gè)基于窗體的認(rèn)證的使用SqlMembershipProvider的Membership framework里,在執(zhí)行Membership功能之前,下面的步驟是必須執(zhí)行的:

1.激活基于窗體的認(rèn)證——正如我們?cè)凇禔n Overview of Forms Authentication》里探討的那樣,我們可以在Web.config文件里將<authentication>元素的mode屬性設(shè)置為Forms來(lái)激活forms authentication.當(dāng)激活后,每次后續(xù)請(qǐng)求抵達(dá)后,都要檢查forms authentication ticket票據(jù),如果有票據(jù),請(qǐng)求就通過(guò)了認(rèn)證.

2.將application services schema添加到恰當(dāng)?shù)臄?shù)據(jù)庫(kù)——當(dāng)使用SqlMembershipProvider時(shí),我們需要將application services schema安裝到一個(gè)數(shù)據(jù)庫(kù)里.通常就是應(yīng)用程序用于存儲(chǔ)數(shù)據(jù)的那個(gè)數(shù)據(jù)庫(kù).文章《Creating the Membership Schema in SQL Server》探討了用aspnet_regsql.exe來(lái)實(shí)現(xiàn).

3.自定義Web Application的設(shè)置以引用第2步里的數(shù)據(jù)庫(kù)——文章《Creating the Membership Schema in SQL Server》探討了2種配置web application以使SqlMembershipProvider調(diào)用第2步選擇的數(shù)據(jù)庫(kù)的方法:要么LocalSqlServer的連接字符串名稱;要么注冊(cè)一個(gè)新的provider,對(duì)該provider進(jìn)行定制,以調(diào)用第2步里選擇的數(shù)據(jù)庫(kù).

當(dāng)開(kāi)始構(gòu)架使用SqlMembershipProvider和基于窗體認(rèn)證的web應(yīng)用程序時(shí),在使用Membership class 或ASP.NET的Login Web control之前我們都必須執(zhí)行這3步.由于我們?cè)谇懊娴奈恼吕镆呀?jīng)執(zhí)行了這3個(gè)步驟,所以我們現(xiàn)在就要使用Membership framework了!


第一步:添加新的ASP.NET頁(yè)面

在本文以及后面的3篇文章,我們將考察各種與Membership相關(guān)的函數(shù)和功能.我們需要一系列的頁(yè)面來(lái)貫徹這些技術(shù)點(diǎn).讓我們創(chuàng)建這些頁(yè)面和一個(gè)網(wǎng)站地圖文件(Web.sitemap)吧.

我們首先在項(xiàng)目里添加一個(gè)名為Membership的文件夾,在里面添加5個(gè)ASP.NET頁(yè)面,將每個(gè)頁(yè)面與Site.master頁(yè)面對(duì)應(yīng)起來(lái):

.CreatingUserAccounts.aspx
.UserBasedAuthorization.aspx
.EnhancedCreateUserWizard.aspx
.AdditionalUserInfo.aspx
.Guestbook.aspx
此時(shí)你的Solution Explorer看起來(lái)和下面的截屏差不多:

Security Tutorials系列文章第五章:Creating User Accounts
圖1

每個(gè)頁(yè)面應(yīng)有2個(gè)Content controls,其中一個(gè)是對(duì)應(yīng)母版頁(yè)的ContentPlaceHolders:
如下:
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" Runat="Server"> </asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="LoginContent" Runat="Server"> </asp:Content>

記得LoginContent ContentPlaceHolder的默認(rèn)代碼將顯示一個(gè)到登錄或注銷的鏈接,這取決于用戶是否通過(guò)了認(rèn)證.不過(guò)我們?cè)贑ontent2 Content控件里重寫(xiě)了母版頁(yè)的默認(rèn)代碼.就像在《An Overview of Forms Authentication tutorial》里探討的那樣,如果我們不希望在頁(yè)面左邊部分顯示與登錄相關(guān)的選項(xiàng)的話,這樣做是很有用的.

不過(guò)對(duì)這5個(gè)頁(yè)面而言,刪除Content2 Content的聲明代碼,這樣一來(lái),這5個(gè)頁(yè)面就只包含1個(gè)Content控件了.


第二步:創(chuàng)建網(wǎng)站地圖

很多網(wǎng)站都有便于用戶導(dǎo)航的用戶界面.該界面可能僅僅包含到站點(diǎn)各個(gè)部分的鏈接;或以菜單或樹(shù)形結(jié)構(gòu)的形式提供鏈接.作為頁(yè)面開(kāi)發(fā)人員,創(chuàng)建這樣的界面僅僅是完成了一半的任務(wù),我們還要將用于導(dǎo)航的邏輯結(jié)構(gòu)便于維護(hù)和更新.比如,當(dāng)添加一個(gè)新的頁(yè)面或?qū)⒛硞€(gè)頁(yè)面刪除時(shí),我們希望對(duì)站點(diǎn)地圖進(jìn)行更新——并且這些改動(dòng)可以通過(guò)導(dǎo)航用戶界面反映出來(lái).

要完成定義站點(diǎn)地圖和執(zhí)行基于站點(diǎn)地圖的導(dǎo)航界面這2個(gè)任務(wù)是很容易的,當(dāng)然這要?dú)w功于ASP.NET 2.0里的Site Map framework和Navigation Web控件. Site Map framework允許開(kāi)發(fā)人員定義一個(gè)站點(diǎn)地圖,并通過(guò)API(具體說(shuō)就是SiteMap class)來(lái)進(jìn)行訪問(wèn).而內(nèi)置的Navigation Web控件包括Menu control,TreeView control,以及SiteMapPath控件.

與Membership和Roles frameworks一樣,Site Map framework也是采用的provider模式.Site Map provider class的作用就是在內(nèi)存里生成一個(gè)供SiteMap class使用的構(gòu)造器(in-memory structure),而SiteMap class從一個(gè)持久的數(shù)據(jù)存儲(chǔ)——比如XML文件或一個(gè)數(shù)據(jù)庫(kù)表.

在.NET Framework里以及包含了一個(gè)默認(rèn)的Site Map provider(也就是XmlSiteMapProvider),它從一個(gè)XML文件里讀取站點(diǎn)地圖數(shù)據(jù),本文使用的就是XmlSiteMapProvider.對(duì)Site Map provider的更多資料請(qǐng)參閱本文結(jié)尾處的外延閱讀.

該默認(rèn)的Site Map provider需要用到根目錄下一個(gè)叫Web.sitemap的XML文件,因此我們要添加它.在項(xiàng)目的Solution Explorer上右擊鼠標(biāo),選“Add New”項(xiàng),在對(duì)話框里選擇添加一個(gè)名為Web.sitemap的Site Map類型的文件.

Security Tutorials系列文章第五章:Creating User Accounts
圖2:


該XML站點(diǎn)地圖文件以層次結(jié)構(gòu)的形式定義了站點(diǎn)的結(jié)構(gòu).這些層次結(jié)構(gòu)關(guān)系是在該XML文件的<siteMapNode>元素里定義的.該Web.sitemap文件必須以一個(gè)<siteMap>節(jié)點(diǎn)開(kāi)始,其下面剛好有一個(gè)<siteMapNode>子節(jié)點(diǎn).最頂層的<siteMapNode>元素代表的是站點(diǎn)體系結(jié)構(gòu)的根節(jié)點(diǎn),其下可有任意數(shù)量的派生節(jié)點(diǎn).每個(gè)<siteMapNode>元素必須包含一個(gè)title屬性,以及可選的url 和 description屬性,以及其它的節(jié)點(diǎn).每個(gè)非空的url屬性必須是全局唯一的.

在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>

上述代碼定義的層次體系結(jié)構(gòu)如下所示:

Security Tutorials系列文章第五章:Creating User Accounts

圖3:


第三步:在母版頁(yè)里添加一個(gè)可導(dǎo)航的用戶界面

ASP.NET里與導(dǎo)航相關(guān)的控件有Menu, TreeView,以及SiteMapPath.其中Menu和TreeView
控件分別以菜單和樹(shù)形結(jié)構(gòu)的形式呈現(xiàn)站點(diǎn)的層次結(jié)構(gòu).SiteMapPath控件則有所不同,它按照層次結(jié)構(gòu)將用戶當(dāng)前訪問(wèn)的節(jié)點(diǎn),及其父節(jié)點(diǎn),以此類推地將各層顯示出來(lái).我們可以用SiteMapDataSource將站點(diǎn)地圖數(shù)據(jù)綁定到其它的Web控件上,也可以通過(guò)SiteMap class,以編程的方式訪問(wèn)站點(diǎn)地圖數(shù)據(jù).

對(duì)Site Map framework 和 Navigation controls的深入探討以及超出了本系列文章的范圍,為了簡(jiǎn)便,我們使用《Working with Data in ASP.NET 2.0》這個(gè)系列文章所用過(guò)的導(dǎo)航用戶界面.它通過(guò)一個(gè)Repeater控件來(lái)展示導(dǎo)航鏈接,如圖4所示.


Adding a Two-Level List of Links in the Left Column


為了創(chuàng)建這樣的導(dǎo)航界面,在Site.master母版頁(yè)的左邊,也就是文本“TODO: Menu will go here...”所在的地方添加如下的聲明代碼:

<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" />

上述代碼將一個(gè)名為menu的Repeater控件綁定到一個(gè)SiteMapDataSource控件,該控件返回的是Web.sitemap里定義的站點(diǎn)地圖的層次結(jié)構(gòu).

由于SiteMapDataSource控件的ShowStartingNode屬性設(shè)置為False,因此它返回的層次結(jié)構(gòu)是從“Home”節(jié)點(diǎn)的派生節(jié)點(diǎn)開(kāi)始的.該Repeater控件將每個(gè)派生節(jié)點(diǎn)(目前就只有“Membership”)在一個(gè)<li>元素里顯示出來(lái).此外,在Repeater內(nèi)部,還將當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)也顯示在一個(gè)鑲套的列表里.

圖4顯示的是將我們?cè)诘诙嚼锒x的站點(diǎn)地圖的層次結(jié)構(gòu)顯示出來(lái)的效果.而在Styles.css文件里定義的層疊式樣式表(CSS)負(fù)責(zé)顯示效果.

對(duì)上述代碼的工作原理的深入探討請(qǐng)參閱《Master Pages and Site Navigation》系列文章.

Security Tutorials系列文章第五章:Creating User Accounts

圖4


Adding Breadcrumb Navigation

除了在左邊列出一系列的鏈接外,我們也要在每頁(yè)上顯示一個(gè)breadcrumb.所謂的breadcrumb就是一個(gè)導(dǎo)航用戶界面元件,它可以顯示用戶當(dāng)前所在位置位于站點(diǎn)結(jié)構(gòu)的對(duì)應(yīng)層次.SiteMapPath控件利用Site Map framework來(lái)確定當(dāng)前頁(yè)面在站點(diǎn)地圖的位置,然后根據(jù)該信息顯示一個(gè)breadcrumb.


具體來(lái)說(shuō),在母版頁(yè)頭部的<div>元素里添加一個(gè)<span>元素,將該<span>元素的class屬性設(shè)置為“breadcrumb”(在Styles.css里有對(duì)“breadcrumb”的相應(yīng)規(guī)則).接下來(lái),在該<span>元素里添加一個(gè)新的SiteMapPath:

<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顯示的是當(dāng)訪問(wèn)~/Membership/CreatingUserAccounts.aspx頁(yè)面時(shí)候的SiteMapPath控件的效果

圖5


第四步:移除自定義的Principal 和 Identity邏輯

在文章《Forms Authentication Configuration and Advanced Topics》里,我們看到了如何將通過(guò)認(rèn)證的用戶和我們自定義的principal 和 identity對(duì)象聯(lián)系起來(lái)。

雖然在某些情況下自定義的principal 和 identity對(duì)象很有用,但在絕大多數(shù)情況下,僅用GenericPrincipal 和 FormsIdentity對(duì)象就完全夠應(yīng)付了.因此,我覺(jué)得使用默認(rèn)的處理方式就行了.為此,我們要么將PostAuthenticateRequest事件處理器刪除或注釋掉,要么直接將Global.asax文件刪除.


第五步:編程創(chuàng)建新用戶

要通過(guò)Membership framework創(chuàng)建一個(gè)新用戶帳戶,要用到Membership class的CreateUser方法.該方法接受username, password,以及其他和用戶相關(guān)的輸入?yún)?shù).當(dāng)調(diào)用該方法時(shí),它將新用戶帳戶的創(chuàng)建委托給配置好的Membership provider,再返回一個(gè)反映剛剛創(chuàng)建的用戶帳戶的MembershipUser對(duì)象.


該CreateUser方法有4個(gè)重載,每個(gè)重載都接受數(shù)目不同的輸入?yún)?shù):

.CreateUser(username, password)

.CreateUser(username, password, email)

.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, MembershipCreateStatus)

.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, MembershipCreateStatus)


這四個(gè)重載的不同在于輸入?yún)?shù)的數(shù)目不同而已.為什么有這些重載方法呢?因?yàn)閯?chuàng)建一個(gè)新用戶帳戶所需要的信息取決于Membership provider的配置情況.在文章《Creating the Membership Schema in SQL Server》里我們考察了在Web.config文件里設(shè)置Membership provider的配置選項(xiàng).

需要注意的是requiresQuestionAndAnswer屬性的設(shè)置.如果將它設(shè)置為true (默認(rèn)值),當(dāng)創(chuàng)建一個(gè)新帳戶時(shí),必須指定具體的安全提示問(wèn)題和答案,當(dāng)以后用戶需要重新設(shè)置密碼的時(shí)候需要這些信息.當(dāng)其設(shè)置為true時(shí),調(diào)用頭2個(gè)重載函數(shù)將拋出一個(gè)異常,因?yàn)闆](méi)有安全提示問(wèn)題和答案信息.因此我們必須使用最后2個(gè)重載函數(shù)之一.


為了演示CreateUser方法的使用,讓我們創(chuàng)建一個(gè)用戶界面,供用戶提供name, password, email,安全提示問(wèn)題和答案等信息.我們?cè)贛embership文件夾里打開(kāi)CreatingUserAccounts.aspx頁(yè)面,添加如下的Content控件:

.一個(gè)id為Username的TextBox控件
.一個(gè)id為Password的TextBox控件,其TextMode屬性為Password
.一個(gè)id為Email的TextBox控件
.一個(gè)id為SecurityQuestion的Label控件,清除其Text屬性
.一個(gè)id為SecurityAnswer的TextBox控件
.一個(gè)id為CreateAccountButton的Button控件,其TextMode屬性為“Create the User Account”
. 一個(gè)id為CreateAccountResults的Label控件,清除其Text屬性


這樣一來(lái),你的界面看起來(lái)應(yīng)該和下面的差不多:

Security Tutorials系列文章第五章:Creating User Accounts

圖6


我們注意到這些安全提示問(wèn)題和密碼都是依照user-by-user的原則,這樣才可能允許每個(gè)用戶定義其自己的安全提示問(wèn)題.就本例而言,我們決定采用一個(gè)很常見(jiàn)的安全提示問(wèn)題:“你最喜歡的是什么顏色?”

為了貫徹該安全提示問(wèn)題,我們?cè)陧?yè)面的后臺(tái)代碼類里添加一個(gè)名為passwordQuestion的常量,用于存儲(chǔ)該安全提示問(wèn)題,在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;
}


接下來(lái),為CreateAccountButton的Click事件創(chuàng)建一個(gè)事件處理器:

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;
}
}


在該事件處理器里我們開(kāi)始創(chuàng)建了一個(gè)類型為MembershipCreateStatus的名為createStatus的變量.MembershipCreateStatus用于指明CreateUser操作的情況.比如,如果創(chuàng)建用戶帳戶成功,那么MembershipCreateStatus的實(shí)例的值就會(huì)被賦值為Success;而如果系統(tǒng)已經(jīng)存在該用戶名,那么值就被賦值為DuplicateUserName;在上面我們使用的重載函數(shù)里,我們必須傳遞一個(gè)MembershipCreateStatus實(shí)例作為out參數(shù),在CreateUser方法內(nèi)部,將對(duì)該輸出參數(shù)賦一個(gè)恰當(dāng)?shù)闹?我們通過(guò)考察該參數(shù)的值來(lái)判斷用戶帳戶是否創(chuàng)建成功.

當(dāng)調(diào)用CreateUser方法,傳入createStatus輸出參數(shù)后,我們用一個(gè)switch聲明來(lái)輸出一個(gè)相應(yīng)的消息,當(dāng)然這取決于createStatus的值.

圖7顯示的是當(dāng)成功創(chuàng)建一個(gè)用戶帳戶時(shí)的輸出界面;而圖8和圖9顯示的是創(chuàng)建失敗是界面.其中,圖8是因?yàn)楫?dāng)用戶輸入的是5位的密碼,低于系統(tǒng)要求的最短長(zhǎng)度,而圖9是因?yàn)橐獎(jiǎng)?chuàng)建的用戶已經(jīng)在系統(tǒng)里存在了(我們?cè)趫D7里就創(chuàng)建了該用戶).

Security Tutorials系列文章第五章:Creating User Accounts

圖7

Security Tutorials系列文章第五章:Creating User Accounts
圖8

Security Tutorials系列文章第五章:Creating User Accounts

圖9
注意:
你可能想知道,如果使用頭2種重載方法來(lái)創(chuàng)建用戶帳戶的話,如何來(lái)判斷是否創(chuàng)建成功呢?比較2個(gè)這重載沒(méi)有類型為MembershipCreateStatus的輸出參數(shù).實(shí)際上,如果創(chuàng)建失敗的話,這2種重載方法將拋出一個(gè)MembershipCreateUserException異常,該異常就包含一個(gè)類型為MembershipCreateStatus的StatusCode屬性.

創(chuàng)建一些用戶帳戶,然后在SecurityTutorials.mdf數(shù)據(jù)庫(kù)里的aspnet_Users 和 aspnet_Membership表里檢驗(yàn)這些帳戶信息,如圖10所示,我在CreatingUserAccounts.aspx頁(yè)面里創(chuàng)建了2個(gè)用戶:Tito 和 Bruce.

Security Tutorials系列文章第五章:Creating User Accounts
圖10

雖然Membership用戶存儲(chǔ)現(xiàn)在包含了Bruce 和 Tito的帳戶信息,但我們還沒(méi)有實(shí)現(xiàn)允許Bruce 或 Tito登錄站點(diǎn)的功能.目前,Login.aspx頁(yè)面是對(duì)硬編碼的username/password驗(yàn)證用戶信息——而不是通過(guò)Membership framework來(lái)進(jìn)行驗(yàn)證.在下一章《Validating User Credentials Against the Membership User Store》里,我們會(huì)對(duì)該頁(yè)進(jìn)行改動(dòng)以對(duì)Membership用戶存儲(chǔ)的用戶帳戶信息進(jìn)行驗(yàn)證.
注意:
如果你沒(méi)有在SecurityTutorials.mdf數(shù)據(jù)庫(kù)里看到任何用戶帳戶信息的話,很可能是
因?yàn)槟愕膚eb應(yīng)用程序使用的是默認(rèn)的Membership provider——AspNetSqlMembershipProvider,它使用的是ASPNETDB.mdf數(shù)據(jù)庫(kù)作為它的用戶存儲(chǔ).要解決這個(gè)問(wèn)題,在Solution Explorer里點(diǎn)“刷新”.如果在App_Data文件夾里添加了一個(gè)ASPNETDB.mdf數(shù)據(jù)庫(kù),那就說(shuō)明就是這個(gè)原因.你可以返回《Creating the Membership Schema in SQL Server》文章的第四步,看如何恰當(dāng)?shù)嘏渲肕embership provider.

創(chuàng)建用戶帳戶的絕大多數(shù)情形是訪問(wèn)者在某個(gè)界面里輸入他們的username, password, email,以及其他的必要信息,然后基于這些信息來(lái)創(chuàng)建用戶帳戶.在這一步,我們看如何手動(dòng)添加這樣的界面,以及如何以編程的方式用Membership.CreateUser方法來(lái)創(chuàng)建用戶帳戶.我們的代碼

僅僅創(chuàng)建新帳戶,而沒(méi)有進(jìn)行其它的處理,比如讓剛剛創(chuàng)建的帳戶處于登錄狀態(tài),或向用戶發(fā)送一個(gè)確認(rèn)電郵等.這些額外的功能需要在按鈕的Click事件處理器里添加相應(yīng)的代碼.

ASP.NET里有一個(gè)CreateUserWizard控件,它就是設(shè)計(jì)來(lái)處理創(chuàng)建用戶帳戶的.包括創(chuàng)建用戶帳戶的用戶界面,在Membership framework里創(chuàng)建帳戶,以及其他相關(guān)的功能,比如發(fā)送一個(gè)確認(rèn)電郵、使剛剛創(chuàng)建的帳戶登錄站點(diǎn)等.使用該控件很簡(jiǎn)單,在絕大多數(shù)情況下不寫(xiě)一行代碼就可以滿足我們的需要,在第六步里我們將詳細(xì)的探討這個(gè)極棒的控件.

雖然使用CreateUserWizard控件我們不寫(xiě)一行代碼就可以滿足我們的需要,但是在某些情況下我們還是要用到CreateUser方法,比如你想對(duì)創(chuàng)建帳戶的用戶體驗(yàn)進(jìn)行高度的定制,或你不想用CreateUserWizard控件的那種用戶界面來(lái)創(chuàng)建用戶帳戶.比如,你可能有這樣 的一個(gè)頁(yè)面,允許用戶上載一個(gè)包含用戶信息的XML文件,該頁(yè)面將對(duì)XML文件的內(nèi)容進(jìn)行解析,再調(diào)用CreateUser方法來(lái)創(chuàng)建一個(gè)新的用戶帳戶.


第六步:Creating a New User with the CreateUserWizard Control

ASP.NET里有一些Login Web控件,這些控件在常見(jiàn)的與用戶帳戶或登錄相關(guān)的場(chǎng)合下都是很有適用的.CreateUserWizard控件就是其中一個(gè).


和其他與登錄相關(guān)的控件一樣,我們不寫(xiě)一行代碼就可以使用CreateUserWizard控件.它根據(jù)Membership provider的配置呈現(xiàn)一個(gè)相應(yīng)的注冊(cè)界面,當(dāng)用戶輸入必要的帳戶信息并點(diǎn)擊“Create User”按鈕后,它就在內(nèi)部調(diào)用Membership類的CreateUser方法創(chuàng)建帳戶.我們可以對(duì)CreateUserWizard控件進(jìn)行高度的定制.在創(chuàng)建用戶帳戶的不同階段可以觸發(fā)很多的事件,如果有必要的話,我們可以創(chuàng)建一個(gè)事件處理器,執(zhí)行我們自己的處理邏輯.
此外,CreateUserWizard控件的外觀也是很靈活的.有很多的屬性來(lái)控制其默認(rèn)界面,如果有必要的話,我們也可以將它轉(zhuǎn)化為一個(gè)模板,或添加我們自己的處理步驟.


Examining the CreateUserWizard’s Default Interface and Behavior

返回Membership文件夾里的CreatingUserAccounts.aspx頁(yè)面,切換到設(shè)計(jì)或分割模式,在頁(yè)面頂端添加一個(gè)CreateUserWizard.設(shè)其ID為RegisterUser,如圖11所示,在控件默認(rèn)的界面包含用于輸入username, password,電郵地址,安全提示問(wèn)題和答案的文本框.

Security Tutorials系列文章第五章:Creating User Accounts
圖11


將CreateUserWizard控件生成的默認(rèn)界面與我們?cè)诘谖宀絼?chuàng)建的界面進(jìn)行比較.最開(kāi)始,CreateUserWizard控件允許注冊(cè)者指定安全提示問(wèn)題和答案,而在我們手動(dòng)添加的界面里使用的是預(yù)先定義好了的安全提示問(wèn)題.該控件的界面還包含了驗(yàn)證控件,而我們手動(dòng)添加的界面卻沒(méi)有對(duì)表單域進(jìn)行驗(yàn)證.另外,該控件的界面里還有一個(gè)“Confirm Password” 文本框(同時(shí)還有一個(gè)CompareValidator控件,確保用戶在“Password” 和 “Compare Password”文本框里輸入的內(nèi)容是一樣的).

有趣的是CreateUserWizard控件將根據(jù)Membership provider的配置情況來(lái)呈現(xiàn)相應(yīng)的用戶界面.比如,只有requiresQuestionAndAnswer設(shè)置為T(mén)rue時(shí),才會(huì)顯示question 和 answer文本框.同樣的,CreateUserWizard控件還會(huì)自動(dòng)添加一個(gè)RegularExpressionValidator控件以確保密碼長(zhǎng)度合乎要求.還會(huì)根據(jù)minRequiredPasswordLength, minRequiredNonalphanumericCharacters, 和passwordStrengthRegularExpression這3個(gè)配置選項(xiàng)的情況來(lái)設(shè)置ErrorMessage 和ValidationExpression屬性.

正如其名字暗示的那樣,CreateUserWizard控件源于Wizard控件. 而Wizard控件提供了一個(gè)界面以處理多步驟的任務(wù).Wizard控件可以有任意數(shù)量的WizardSteps,每個(gè)WizardSteps都是一個(gè)模板,可以在里面定義該步要使用到的HTML 和 Web控件. Wizard控件最開(kāi)始顯示的是第一個(gè)WizardStep,還有便于用戶向前一步或向后一步的導(dǎo)航控件.


就像圖11里的聲明代碼顯示的那樣,CreateUserWizard控件默認(rèn)的界面包含了2個(gè)WizardSteps:

.CreateUserWizardStep——呈現(xiàn)一個(gè)界面供用戶輸入注冊(cè)信息,這也是圖11顯示的那個(gè)界面.

.CompleteWizardStep——顯示一條消息,指出用戶帳戶已經(jīng)成功創(chuàng)建了.

我們可以對(duì)CreateUserWizard的界面和行為進(jìn)行定制,方法就是將這些步驟轉(zhuǎn)化成模板,或添加你自己的WizardSteps.我們將在后面的文章《Storing Additional User Information》里進(jìn)行探討.

讓我們看看一個(gè)實(shí)際的CreateUserWizard控件.通過(guò)瀏覽器訪問(wèn)CreatingUserAccounts.aspx頁(yè)面.在其界面里輸入一些無(wú)效的數(shù)值.比如,密碼長(zhǎng)度不足,或?qū)ⅰ癠ser Name” 文本框置空.這樣,CreateUserWizard控件會(huì)顯示一個(gè)相應(yīng)的錯(cuò)誤信息.圖12顯示的是輸入的不當(dāng)密碼時(shí)的顯示的界面.

Security Tutorials系列文章第五章:Creating User Accounts
圖12


接下來(lái),在CreateUserWizard控件里輸入恰當(dāng)?shù)闹担c(diǎn)“Create User”按鈕.假定所有的輸入都合乎要求,CreateUserWizard控件將通過(guò)Membership framework創(chuàng)建一個(gè)新的用戶帳戶,然后顯示CompleteWizardStep界面,如圖13所示.在該過(guò)程中,CreateUserWizard在內(nèi)部調(diào)用Membership.CreateUser方法,和我們?cè)诘谖宀侥菢幼龅囊粯?

Security Tutorials系列文章第五章:Creating User Accounts
圖13


注意:
如你在圖13看見(jiàn)的那樣,CompleteWizardStep界面包含一個(gè)Continue按鈕.現(xiàn)在,當(dāng)你點(diǎn)擊它時(shí),僅僅執(zhí)行一個(gè)頁(yè)面回傳而已.在下面的“Customizing the CreateUserWizard’s Appearance and Behavior Through Its Properties”部分,我們將看到,當(dāng)你點(diǎn)擊它時(shí),如何導(dǎo)航到Default.aspx頁(yè)面(或其它什么頁(yè)面).


創(chuàng)建一個(gè)新用戶帳戶后,查看aspnet_Users 和 aspnet_Membership表,就像我們?cè)趫D10做的那樣,驗(yàn)證帳戶是否成功創(chuàng)建.


Customizing the CreateUserWizard’s Behavior and Appearance Through Its Properties


我們可以通過(guò)多種途徑對(duì)CreateUserWizard進(jìn)行定制,比如:屬性、WizardSteps,以及event handler.在本節(jié),我們考察如何通過(guò)其屬性來(lái)對(duì)控件的外觀進(jìn)行控制.在下一節(jié),我們看如何通過(guò)event handler來(lái)擴(kuò)展控件的行為.

實(shí)際上,CreateUserWizard控件默認(rèn)界面的所有text都可以通過(guò)眾多的屬性進(jìn)行定制.比如,“User Name”, “Password”, “Confirm Password”, “E-mail”, “Security Question”, 和 “Security Answer”這些label都可以分別通過(guò)UserNameLabelText, PasswordLabelText, ConfirmPasswordLabelText, EmailLabelText, QuestionLabelText, 以及AnswerLabelText屬性進(jìn)行定制.同理,我們還可以在CreateUserWizardStep 和CompleteWizardStep里指定“Create User” 和“Continue”按鈕的文本,還可以指定這些按鈕是Buttons,

LinkButtons,還是ImageButtons.

對(duì)colors, borders, fonts以及其它的視覺(jué)元素,我們可以通過(guò)一系列的style屬性來(lái)進(jìn)行設(shè)置.CreateUserWizard控件還有一些通用的Web控件屬性——BackColor, BorderStyle, CssClass, Font等等.也有一些屬性用于定義特定部分的外觀,拿TextBoxStyle屬性來(lái)說(shuō),它定義了CreateUserWizardStep里的textboxe的樣式;而TitleTextStyle屬性定義了標(biāo)題(“Sign Up for Your New Account”)的樣式.

除了這些與外觀相關(guān)的屬性外,還有一系列的屬性可以影響CreateUserWizard控件的行為.比如,如果將DisplayCancelButton屬性設(shè)為T(mén)rue(默認(rèn)值為False),那么就會(huì)在“Create User”按鈕旁邊顯示一個(gè)Cancel按鈕,同時(shí)還要記得設(shè)置CancelDestinationPageUrl屬性,它用于指定當(dāng)用戶點(diǎn)擊Cancel按鈕后將用戶導(dǎo)航到哪個(gè)頁(yè)面.另外,就像我們?cè)谏弦还?jié)提到的那樣,點(diǎn)擊CompleteWizardStep里的Continue按鈕,僅僅產(chǎn)生一個(gè)頁(yè)面回傳,如果點(diǎn)擊該按鈕后,想將用戶導(dǎo)航到其它某個(gè)頁(yè)面的話,只需要為ContinueDestinationPageUrl屬性指定一個(gè)URL即可.

我們來(lái)對(duì)RegisterUser CreateUserWizard控件進(jìn)行改動(dòng),以包含一個(gè)Cancel按鈕,并且當(dāng)用戶點(diǎn)擊Cancel或Continue按鈕時(shí)將用戶導(dǎo)航到Default.aspx頁(yè)面. 為此,設(shè)置 DisplayCancelButton屬性為T(mén)rue,并將CancelDestinationPageUrl 和 ContinueDestinationPageUrl屬性設(shè)為“~/Default.aspx”. 如圖14所示的是改動(dòng)后的CreateUserWizard控件.


圖14


當(dāng)訪問(wèn)者輸入username, password, email address,以及安全提示問(wèn)題和答案,點(diǎn)“Create User”后,將創(chuàng)建一個(gè)新帳戶,并以剛創(chuàng)建的

那個(gè)帳戶登錄站點(diǎn).不過(guò)還有一種情況,比如,你可能想讓Administrator來(lái)創(chuàng)建一個(gè)新帳戶,但創(chuàng)建成功后依然以 Administrator的身份登錄

站點(diǎn),而不是以剛創(chuàng)建的那個(gè)新帳戶登錄站點(diǎn),這就需要修改LoginCreatedUser屬性的布爾值了.

Membership framework里的User account包含一個(gè)approved(審核)標(biāo)記;凡是未通過(guò)審核的的用戶是無(wú)法登錄站點(diǎn)的.默認(rèn)下,新創(chuàng)建的用

戶帳戶都標(biāo)記為approved,允許這些帳戶馬上登錄站點(diǎn).不過(guò)有可能我們需要把新帳戶標(biāo)記為unapproved(未審核).比如,我們希望

Administrator手動(dòng)進(jìn)行審核,或你希望檢查用戶提供的電子郵件地址真實(shí)有效后才允許他們登錄站點(diǎn).無(wú)論是哪種情況,如果你希望將新創(chuàng)建

的用戶標(biāo)記為unapproved的話,只需要將DisableCreatedUser屬性設(shè)置為T(mén)rue(默認(rèn)為False)即可.


其它我們還應(yīng)該注意的與行為相關(guān)的屬性包括AutoGeneratePassword 和 MailDefinition.如果AutoGeneratePassword屬性設(shè)置為T(mén)rue,那

么CreateUserWizardStep就不會(huì)顯示“Password”和“Confirm Password”文本框,而是調(diào)用Membership類的 GeneratePassword方法自動(dòng)地為

用戶創(chuàng)建密碼.

如果在創(chuàng)建帳戶的過(guò)程中,你想向用戶提供的電郵地址發(fā)送郵件的話,MailDefinition屬性就可以派上用場(chǎng)了.該屬性包含一系列的模板

(subproperties),來(lái)確定電郵發(fā)送的內(nèi)容.這些模板包括諸如Subject, Priority, IsBodyHtml, From, CC,和BodyFileName的選項(xiàng).其中

BodyFileName屬性指明了郵件內(nèi)容主體包含的text或HTML文件.該內(nèi)容主體包含2個(gè)預(yù)定義的占位符:<%UserName%>和<%Password%>.如果這些占

位符包含在BodyFileName文件里,那么將被剛創(chuàng)建的用戶帳戶的name 和 password替換掉.
注意:
CreateUserWizard控件的MailDefinition屬性僅僅指定了郵件消息的細(xì)節(jié),而并沒(méi)有指定郵件實(shí)際發(fā)送的細(xì)節(jié)(也就是說(shuō),是使用的SMTP server還是mail drop directory等等細(xì)節(jié)).這些底層細(xì)節(jié)需要在Web.config文件的<system.net>節(jié)點(diǎn)定義.關(guān)于如何設(shè)置這些配置,以及在ASP.NET 2.0里發(fā)送郵件的大體情況的更多詳情,請(qǐng)參閱站點(diǎn)FAQs at SystemNetMail.com,以及我的文章《Sending Email in ASP.NET 2.0》.


Extending the CreateUserWizard’s Behavior Using Event Handlers

CreateUserWizard控件在處理過(guò)程中會(huì)觸發(fā)一系列的事件.比如,當(dāng)用戶輸入信息后,點(diǎn)擊“Create User”按鈕時(shí),將觸發(fā)CreatingUser事件;如果,在創(chuàng)建過(guò)程中發(fā)生任何問(wèn)題將觸發(fā)CreateUserError事件;如果創(chuàng)建成功,就會(huì)觸發(fā)CreatedUser事件.還有其它的事件,不過(guò)這3個(gè)是最常見(jiàn)的事件.

在某些情況下,我們可能需要介入CreateUserWizard的處理流程,為某個(gè)特定的事件創(chuàng)建一個(gè)事件處理器.我們來(lái)做個(gè)演示,使RegisterUser CreateUserWizard控件對(duì)username 和 password執(zhí)行自定義驗(yàn)證.具體來(lái)說(shuō),username前后不能有空格,且username和password不能連在一起.簡(jiǎn)單的說(shuō),用戶名不能為"Scott ", 或username/password不能連在一起,如“Scott.1234”.

為此,我們?yōu)镃reatingUser事件創(chuàng)建一個(gè)事件處理器以執(zhí)行額外的驗(yàn)證檢查.如果輸入的數(shù)據(jù)有問(wèn)題就取消創(chuàng)建流程.我們也需要在頁(yè)面上添加一個(gè)Label控件,用于顯示一條消息,指出username或password有問(wèn)題.首先,在CreateUserWizard控件下面添加一個(gè)Label控件,設(shè)置其ID為InvalidUserNameOrPasswordMessage,而ForeColor屬性設(shè)為Red.清除其Text屬性,再將EnableViewState 和 Visible屬性設(shè)為False,如下:

<asp:Label runat="server" id="InvalidUserNameOrPasswordMessage" Visible="false" ForeColor="Red" EnableViewState="false">

</asp:Label>

接下來(lái),為CreateUserWizard控件的CreatingUser事件創(chuàng)建一個(gè)事件處理器.要?jiǎng)?chuàng)建一個(gè)事件處理器,切換到設(shè)計(jì)模式,選中該控件,打開(kāi)其屬性窗口.在屬性窗口里點(diǎn)擊閃電圖標(biāo),在相應(yīng)的事件上雙擊以創(chuàng)建對(duì)應(yīng)的事件處理器.在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,可以通過(guò)該控件的UserName 和 Password屬性獲取, 在上述代碼里我們檢查輸入的username是否有前后空格,以及password里是否還包含了username;如果出現(xiàn)了上述情況之一,在InvalidUserNameOrPasswordMessage Label控件里就會(huì)出現(xiàn)一個(gè)出錯(cuò)信息,并將事件處理器的e.Cancel屬性設(shè)置為true. 如果e.Cancel為true,那么CreateUserWizard就取消用戶帳戶創(chuàng)建流程.

Security Tutorials系列文章第五章:Creating User Accounts

圖15:


注意:
在后面的《Storing Additional User Information》文章里,我們將看到使用CreateUserWizard控件的CreatedUser事件的示例.


結(jié)語(yǔ):

Membership類的CreateUser方法在Membership framework里創(chuàng)建一個(gè)新的用戶帳戶.它是通過(guò)將調(diào)用委托給我們配置好的Membership provider,在本文里,也就是SqlMembershipProvider.該CreateUser方法將向aspnet_Users 和 aspnet_Membership數(shù)據(jù)庫(kù)表里添加一條記錄.

如果以編程的方式創(chuàng)建用戶帳戶的話(就像我們?cè)诘谖宀嚼镒龅哪菢?,最快最方便的方式是使用CreateUserWizard控件.它以多步驟的界面方式收集用戶信息,并以此在Membership framework里創(chuàng)建用戶帳戶.在內(nèi)部,該控件使用的是Membership.CreateUser方法,和我們?cè)诘谖宀嚼锬菢幼龅囊粯印V徊贿^(guò)不用手寫(xiě)一行代碼,它就可以提供用戶界面,驗(yàn)證控件,并且可以反映出創(chuàng)建過(guò)程中出現(xiàn)的錯(cuò)誤.

此時(shí),我們完成了創(chuàng)建用戶帳戶的功能。然而,在登錄頁(yè)面,我們是對(duì)第二篇文章里硬編碼的用戶信息進(jìn)行的驗(yàn)證.在下一篇文章里,我們將對(duì)Login.aspx頁(yè)面進(jìn)行更新,對(duì)Membership framework提供的用戶信息進(jìn)行驗(yàn)證.

祝編程快樂(lè)!


作者簡(jiǎn)介:

Scott Mitchell,著有七本ASP/ASP.NET方面的書(shū),是4GuysFromRolla.com的創(chuàng)始人,自1998年以來(lái)一直應(yīng)用微軟Web技術(shù)。Scott是個(gè)獨(dú)立的技術(shù)咨詢顧問(wèn),培訓(xùn)師,作家,最近完成了將由Sams出版社出版的新作,《24小時(shí)內(nèi)精通ASP.NET 2.0》。他的聯(lián)系電郵為 mitchell@4guysfromrolla.com ,也可以通過(guò)他的博客 http://ScottOnWriting.NET 與他聯(lián)系。

Security Tutorials系列文章第五章:Creating User Accounts


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 霍林郭勒市| 乌审旗| 宁陕县| 府谷县| 镇远县| 扶余县| 浦东新区| 清镇市| 衡东县| 台州市| 白银市| 水富县| 阿城市| 阿坝| 通州区| 林芝县| 庆阳市| 北京市| 丹棱县| 房产| 公安县| 扎赉特旗| 定陶县| 江城| 教育| 宝应县| 芜湖市| 汶上县| 株洲市| 大理市| 彭山县| 石楼县| 开平市| 巴彦淖尔市| 临武县| 聊城市| 桦川县| 南宁市| 潞西市| 南雄市| 八宿县|