考察ASP.NET 2.0Membership,Roles,Profile - Part 1
導(dǎo)言: 很多網(wǎng)站都有一個(gè)共同點(diǎn):提供用戶賬號(hào)(user accounts),這些網(wǎng)站允許(或需要)訪問者創(chuàng)建賬號(hào)以使用特定的功能.比如ASPMessageboard.com網(wǎng)站,匿名用戶和注冊(cè)用戶都可以使用搜索功能,但如果要發(fā)表文章或回復(fù)消息的話,訪問者就必須獲得用戶賬號(hào)并登錄網(wǎng)站. 一個(gè)支持用戶賬號(hào)的網(wǎng)站,都要包括這些相同的步驟:創(chuàng)建一個(gè)數(shù)據(jù)庫表來存儲(chǔ)用戶賬號(hào)信息;創(chuàng)建一個(gè)登錄頁面;定義一種系統(tǒng),當(dāng)頁面回傳時(shí)仍可保存注冊(cè)用戶的登錄狀態(tài);指出哪些頁面只對(duì)注冊(cè)用戶可見;創(chuàng)建一個(gè)新頁面供新用戶注冊(cè);創(chuàng)建一個(gè)頁面便于網(wǎng)站管理員管理用戶賬號(hào)等等.在ASP.NET之前,開發(fā)者必須決定如何貫徹這些方面。ASP.NET引入了forms-based authentication的概念,二樓提供了一個(gè)FormsAuthentication class類來便于在網(wǎng)站登錄或注銷.同樣的還有authentication ticket,在頁面請(qǐng)求時(shí)保存用戶的登錄狀態(tài)。(關(guān)于ASP.NET的基于窗體的識(shí)別功能,請(qǐng)參閱文章《Using Forms Authentication in ASP.NET 》和《Dissecting Forms Authentication》) 即便有了基于窗體的識(shí)別功能,ASP.NET開發(fā)者仍然要定義并構(gòu)建相應(yīng)的結(jié)構(gòu)來存儲(chǔ)用戶賬號(hào)信息;創(chuàng)建登錄和注銷的web頁面;還有便于訪問者創(chuàng)建新賬號(hào)和便于管理員管理賬號(hào)的頁面等.感謝ASP.NET 2.0,利用其membership system 和 security Web控件,可以減輕開發(fā)者的負(fù)擔(dān).簡(jiǎn)單的說,membership是一個(gè)API,可以編程訪問與用戶帳戶相關(guān)的任務(wù).比如:有專門的方法創(chuàng)建一個(gè)新的用戶帳戶,識(shí)別用戶身份,刪除用戶,返回所有的用戶信息等.此外,還有很多建立在該API基礎(chǔ)上的security Web控件. 本系列文章將考察2.0版本中的membership, roles,pofile系統(tǒng),以及各種security Web控件.本文我們考察membership的基本原理并配置與使用內(nèi)置的SqlMembershipProvider. 基于窗口的認(rèn)證(Authentication) 在ASP.NET之前,web開發(fā)者必須自己定義所有的認(rèn)證.一個(gè)問題是當(dāng)頁面請(qǐng)求時(shí)如何記住用戶的登錄狀態(tài),也就是說當(dāng)用戶輸入用戶名和密碼并成功登錄后,當(dāng)用戶訪問其它頁面時(shí),網(wǎng)站如何記得該用戶是否成功登錄了?另一個(gè)問題是如何防止頁面被未授權(quán)的用戶訪問,也就是說如何設(shè)置一個(gè)頁面只能被一部分或被授權(quán)的用戶訪問?在經(jīng)典ASP里我們通過使用Session變量來解決這些問題.每個(gè)頁面檢查該Session變量一確定訪問者的身份,以及是否允許他們?cè)L問. 為此,ASP.NET 1.0版提供了對(duì)forms-based authentication的支持,同時(shí)可以在Web.config文件里指定authorization rules角色.forms-based authentication提供了一種方法將authentication ticket作為一個(gè)cookie存儲(chǔ)在瀏覽器里,在發(fā)生web請(qǐng)求的時(shí)候記住用戶的登錄狀態(tài).而FormsAuthentication class類包含了很多方法來處理這些authentication ticket。可以創(chuàng)建它也可以刪除它. 不幸的是forms-based authentication依然留給開發(fā)者很多工作.開發(fā)者仍然必須決定如何傳遞用戶帳戶信息;仍然必須構(gòu)建登錄頁面并編寫使用FormsAuthentication class類的代碼;仍然必須構(gòu)建注銷頁面;構(gòu)建注冊(cè)帳戶頁面;構(gòu)建管理帳戶的頁面等等。ASP.NET 1.0版本引入forms-based authentication的初衷是好的,只是貫徹起來有難度. 在Forms-Based Authentication之上構(gòu)建ASP.NET 2.0的Membership Forms-based authentication依然存在于ASP.NET 2.0版本,使用方法與 1.x版本一樣。同時(shí)在Web.config文件里也有authorization設(shè)置. ASP.NET 2.0版本增加的是membership API以及security Web控件. membership API是通過provider模式來執(zhí)行的.那就意味著當(dāng)定義好界面后可以對(duì)實(shí)際的執(zhí)行過程進(jìn)行定制.而.NET Framework包含了Membership class類,該類包含可很多方法,比如 CreateUser(), GetAllUsers(), ValidateUser()等等. 然而,當(dāng)通過一個(gè)ASP.NET web應(yīng)用程序來使用API的時(shí)候?qū)嶋H調(diào)用的類取決于應(yīng)用程序的配置.你可以定制你的用戶帳戶邏輯,方法是創(chuàng)建一個(gè)執(zhí)行定義好的membership API的類,然后配置web應(yīng)用程序來使用你定義的類.當(dāng)然,你也用不著定義一個(gè)自定義的類——ASP.NET包含了2個(gè)內(nèi)置的membership providers,一個(gè)將用戶帳戶信息存儲(chǔ)在一個(gè)SQL Server數(shù)據(jù)庫;另一個(gè)使用的是實(shí)際的目錄.因此membership system 和 security Web控件都可以被這2個(gè)內(nèi)置的providers使用.如果你確實(shí)自定義了用戶數(shù)據(jù),你也可以創(chuàng)建一個(gè)自定義的provider通過相同的API 和 security控件來使用這些自定義的用戶數(shù)據(jù).關(guān)于provider模式的更多信息,請(qǐng)參閱文章《A Look at ASP.NET 2.0's Provider Model》(http://aspnet./articles/101905-1.aspx) 在本系列的后續(xù)文章里,我們將考察創(chuàng)建用戶自定義的membership provider的詳細(xì)步驟. SqlMembershipProvider——將用戶帳戶數(shù)據(jù)存儲(chǔ)在一個(gè)SQL Server數(shù)據(jù)庫 ASP.NET 2.0 里的SqlMembershipProvider provider使用一個(gè)數(shù)據(jù)庫來存儲(chǔ)認(rèn)證信息.為了使用該provider,你必須創(chuàng)建一個(gè)相應(yīng)的數(shù)據(jù)庫構(gòu)架(schema).可以通過2種方法來完成: 1.使用ASP.NET網(wǎng)站管理工具(這將會(huì)在一個(gè)SQL Server 2005數(shù)據(jù)庫文件ASPNETDB.mdf里創(chuàng)建構(gòu)架,且位于App_Data文件夾) 2.使用ASP.NET SQL Server注冊(cè)工具——使用該工具在一個(gè)SQL Server 2000 或 2005 數(shù)據(jù)庫里創(chuàng)建構(gòu)架. 要使用ASP.NET網(wǎng)站管理工具的話,首先在Visual Studio的Website菜單,選擇“ASP.NET Configuration”項(xiàng),然后在Security項(xiàng)里,將authentication類型改為"From the internet" 。具體方法是:要么點(diǎn)"Select authentication type"鏈接,要么點(diǎn)" "Use the security Setup Wizard to configure security step by step"鏈接.這樣將自動(dòng)在App_Data文件夾里創(chuàng)建一個(gè)名為ASPNETDB.mdf的數(shù)據(jù)庫(我們馬上將考察該數(shù)據(jù)庫的構(gòu)架).關(guān)于使用網(wǎng)站管理工具的更多詳情請(qǐng)參閱文章《Website Administration Tool Overview》(http://msdn2.microsoft.com/en-us/library/yy40ytx0.aspx) 如果你大算將用戶賬號(hào)信息存儲(chǔ)在其它地方——比如App_Data文件夾之外的一個(gè)SQL Server 2000 或SQL Server 2005數(shù)據(jù)庫. 那么你就需要使用ASP.NET SQL Server注冊(cè)工具(aspnet_regsql.exe).該工具具有圖像界面,當(dāng)然你也可以通過命令行來使用它.你可以借助于圖像界面指定在什么地方添加所需要的表.關(guān)于使用該工具的更多詳情,請(qǐng)參閱技術(shù)文檔(http://msdn2.microsoft.com/en-us/library/ms229862.aspx) 注意: 當(dāng)你使用ASP.NET網(wǎng)站管理工具來將authentication類型設(shè)置為"From the internet" ,這將在Web.config文件里添加一行: 程序代碼
<authentication mode="Forms" />
如果你通過ASP.NET SQL Server注冊(cè)工具來創(chuàng)建數(shù)據(jù)庫構(gòu)架的話,你必須手工向Web.config文件添加在行。此外,沒有在App_Data文件夾里的ASPNETDB.mdf數(shù)據(jù)庫里創(chuàng)建構(gòu)架,而是在其它數(shù)據(jù)庫創(chuàng)建的,那么你必須要在Web.config文件里定制membership配置,并指定連接數(shù)據(jù)庫的連接字符串. SqlMembershipProvider將用戶帳戶信息存儲(chǔ)在下面2個(gè)表里: .aspnet_Users -每一個(gè)用戶帳戶一條記錄,存儲(chǔ)最基本的信息.其UserId列唯一的標(biāo)識(shí)用戶身份. .aspnet_Membership—該表的UserId列將該表與aspnet_Users表里的某條特定記錄對(duì)應(yīng)起來.aspnet_Membership表存儲(chǔ)的是與用戶賬號(hào)相關(guān)的數(shù)據(jù): Email, Password, 安全提示問題以及答案等等. 定制SqlMembershipProvider 如果你希望使用SqlMembershipProvider的默認(rèn)配置(那就意味著用戶帳戶信息存儲(chǔ)在App_Data文件夾里的ASPNETDB.mdf數(shù)據(jù)庫里),那么你除了在Web.config文件里指定使用到的窗體認(rèn)證和授權(quán)角色(authorization rules)外,不需要做其它的更改.(對(duì)于窗體認(rèn)證和授權(quán)角色問題,可以通過ASP.NET網(wǎng)站管理工具來指定。關(guān)于在Web.config文件里指定authorization配置的更多信息請(qǐng)參閱文章《 Authentication and Authorization》(http://samples./quickstart/aspplus/doc/authandauth.aspx)和文章《Authorizing Users and Roles》(http://samples./quickstart/aspplus/doc/authorization.aspx) 如果你打算使用另外一個(gè)數(shù)據(jù)庫,或者說改變membership的某些配置(比如:email地址是否是唯一的;密碼的最短長(zhǎng)度; 密碼是純文本還是經(jīng)過加密;安全提示問題和答案是不是必需的等等)的話,你就要在Web.config文件里手動(dòng)輸入XML模塊來指定你自己的用戶配置.(注意:你必須要為applicationName設(shè)置一個(gè)“硬編碼”值,有關(guān)這方面的更多詳情請(qǐng)參閱《Always set the "applicationName" property when configuring ASP.NET 2.0 Membership and other Providers》) 下面的XML代碼顯示了如何定制SqlMembershipProvider設(shè)置。具體來說,屬于黑體字的XML在<membership>元素里對(duì)設(shè)置進(jìn)行定制。在其上還有一個(gè)<connectionString>節(jié)點(diǎn),提供了連接到數(shù)據(jù)庫的連接字符串(我們可以推算出來,該數(shù)據(jù)庫構(gòu)架是使用ASP.NET SQL注冊(cè)工具添加的) : 程序代碼
<configuration>
<connectionStrings> <add name="MyDB" connectionString="..." /> </connectionStrings> <system.web> ... authentication & authorization settings ... <membership defaultProvider="CustomizedProvider"> <providers> <add name="CustomizedProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MyDB" applicationName="ScottsProject" minRequiredPasswordLength="5" minRequiredNonalphanumericCharacters="0" /> </providers> </membership> </system.web> </configuration> ASP.NET 2.0包含了一個(gè)內(nèi)置的名為L(zhǎng)ocalSqlServer的連接字符串,它指向 App_Data文件夾里的ASPNETDB數(shù)據(jù)庫.如果你希望使用默認(rèn)的ASPNETDB數(shù)據(jù)庫,并只改變一些屬性.將connectionStringName配置為L(zhǎng)ocalSqlServer. 在<membership>元素里添加一個(gè)名為CustomizedProvider的新provider,并作為默認(rèn)的membership provider.該自定義provider仍然使用SqlMembershipProvider ;將connectionStringName設(shè)置為MyDB(就是在<connectionStrings>節(jié)點(diǎn)指定的);將applicationName設(shè)置為ScottsProject;將minRequiredPasswordLength設(shè)置為5;將minRequiredNonalphanumericCharacters設(shè)置為0.我們只是對(duì)很少的屬性進(jìn)行自定義設(shè)置,全部屬性清單見《<add> Element for Providers for Membership》。 Security Web控件的簡(jiǎn)單概述 Security Web控件為處理與用戶帳戶相關(guān)的的任務(wù)提供了一個(gè)用戶界面.主要包括7種security user控件: Login控件——該控件呈現(xiàn)為標(biāo)準(zhǔn)的username/password登錄界面.默認(rèn)下,當(dāng)用戶點(diǎn)擊"Login"按鈕時(shí),立即產(chǎn)生頁面回傳,控件調(diào)用Membershipclass類的VerifyUser(username, password)方法來對(duì)用戶進(jìn)行驗(yàn)證,如果驗(yàn)證通過則為用戶創(chuàng)建一個(gè)authentication ticket,否則顯示一個(gè)出錯(cuò)信息. 為L(zhǎng)oginError event事件創(chuàng)建事件處理器,便于當(dāng)用戶為通過驗(yàn)證時(shí)自定義處理步驟;為Authenticate event事件創(chuàng)建事件處理器,以執(zhí)行你個(gè)人的驗(yàn)證邏輯;Login控件包含了很多的屬性供配置,以改變用戶界面的外觀.要完善控件,可以使用LayoutTemplate,下面的截屏為L(zhǎng)ogin控件的默認(rèn)用戶界面: LoginView控件:有時(shí)我們希望根據(jù)訪問者是匿名用戶還是登錄用戶來顯示不同的內(nèi)容:比如,當(dāng)一個(gè)匿名用戶訪問主頁時(shí)你可能希望顯示一個(gè)Login Web控件,而如果是一個(gè)登錄用戶的話,我們希望顯示一個(gè)消息,比如:"Welcome back, username" ,再附加一個(gè)注銷的鏈接. LoginView控件提供了2個(gè)模板:AnonymousTemplate 和 LoggedInTemplate模板.將顯示給匿名用戶的Web控件和HTML標(biāo)記放在AnonymousTemplate模板里;而將顯示給登錄用戶看的放在LoggedInTemplate模板;此外該控件還可以根據(jù)登錄者角色的不同顯示不同的界面. PasswordRecovery控件-允許用戶重新獲取現(xiàn)有的密碼或?qū)⒁粋€(gè)新密碼傳遞到用戶的電子郵件地址.如果密碼在存儲(chǔ)時(shí)經(jīng)過哈希算法處理,那么“重新獲取”密碼實(shí)際上是創(chuàng)建一個(gè)新的隨機(jī)的密碼,再送回給你.如果密碼是純文本或經(jīng)過加密處理,那么將把現(xiàn)有密碼送回給用戶. LoginStatus控件—如果是匿名用戶,該控件將顯示一個(gè)轉(zhuǎn)到登錄頁面的連接;如果是登錄用戶將顯示一個(gè)注銷鏈接. LoginName控件——該控件僅僅將登錄用戶的username顯示出來。另外,可以通過User.Identity.Name,編程訪問用戶的名稱. CreateUserWizard控件——除了登錄的頁面外,我們還需要一個(gè)供訪問者注冊(cè)的頁面。而CreateUserWizard控件就提供了創(chuàng)建用戶賬號(hào)所需的用戶界面,當(dāng)用戶輸入必需的數(shù)據(jù)并點(diǎn)"Create User"按鈕時(shí),將調(diào)用Membership class類的 CreateUser(...)方法.如果需要的話,可以用templates對(duì)CreateUserWizard控件進(jìn)行定制.下面的截屏為運(yùn)行中的CreateUserWizard控件. 同樣可以對(duì)CreateUserWizard控件的布局和參數(shù)進(jìn)行定制,詳情見《Customizing the CreateUserWizard Control》(http://aspnet./articles/070506-1.aspx) ChangePassword控件——該控件允許用戶改變其密碼 所有的security Web控件在使用的時(shí)候可以不用寫一行代碼。比如你要?jiǎng)?chuàng)建一個(gè)登錄頁面,你只需要?jiǎng)?chuàng)建一個(gè)Login.aspx頁面并拖一個(gè)Login控件到頁面上。瞧,就這么簡(jiǎn)單,不用寫一行代碼。此外security Web控件包含了豐富的事件模型,你可以編程處理各種不同的事件.在本文的下載內(nèi)容里包含了幾個(gè)頁面演示如何使用這些控件. 編程使用Membership System 可以通過Membership class類來使用membership system的函數(shù),比如: GetAllUsers(), CreateUser(), DeleteUser()等等.你可以通過security Web控件在使用這些方法,也可以直接從ASP.NET頁面調(diào)用這些方法.比如你可以創(chuàng)建一個(gè)頁面來列出所有的用戶,方法是將Membership.GetAllUsers()返回的結(jié)果綁定到一個(gè)GridView控件上。在本文下載內(nèi)容里有幾個(gè)編程使用Membership class類的示例. 結(jié)語: 由于很多網(wǎng)站需要用戶賬號(hào)支持,所以ASP.NET對(duì)該功能的支持是很有意義的.不過在ASP.NET 1.0版本里面,本目標(biāo)只達(dá)到了一半。雖然基于窗口的驗(yàn)證提供了標(biāo)準(zhǔn)的手段包含一個(gè)authentication ticket來維系用戶的登錄狀態(tài),但無法存儲(chǔ)用戶帳戶信息或創(chuàng)建必要的web頁面(比如:登錄、創(chuàng)建帳戶等等)。在2.0版本,ASP.NET包含了membership服務(wù)和一些security Web控件.以彌補(bǔ)1.x版本的不足. 在本文,我們考察了membership system的注意目標(biāo),一個(gè)其中一個(gè)內(nèi)置的membership providers——SqlMembershipProvider.該SqlMembershipProvider將用戶帳戶信息存儲(chǔ)在一個(gè)SQL Server數(shù)據(jù)庫,我們也可以通過Web.config文件對(duì)其進(jìn)行用戶定制。此外我們還總覽了ASP.NET的security Web控件.它用來執(zhí)行登錄、創(chuàng)建用戶帳戶,以及其他與用戶帳戶相關(guān)的用戶界面元素. 除了membership system外,ASP.NET 2.0還包含了roles 和 profile system.我們將在后面的文章探討它們. 祝編程快樂! 考察Membership, Roles, 和Profile - Part 2 導(dǎo)言: 在Part 1我們已經(jīng)提到Membership class類包含很多方法可以用來創(chuàng)建、刪除、修改、檢索、驗(yàn)證用戶.由于每個(gè)開發(fā)者的需求不同,Membership class類被設(shè)計(jì)為使用provider模式。這就意味著membership framework在實(shí)際的執(zhí)行過程中可以進(jìn)行用戶定制.ASP.NET包含有SqlMembershipProvider和ActiveDirectoryMembershipProvider,如果有必要的話,你可以構(gòu)建自己的provider. 很多網(wǎng)站需要將用戶劃分為不同的角色.對(duì)于處于某種角色的用戶,要指定其可以訪問哪些頁面、可以看到頁面的哪些內(nèi)容、頁面某些區(qū)域的內(nèi)容對(duì)用戶是可編輯還是只讀.使用ASP.NET 2.0的roles service的話,對(duì)用戶進(jìn)行角色劃分、基于角色的功能和驗(yàn)證都比較簡(jiǎn)單了.與membership service類似,我們可以創(chuàng)建、刪除role,對(duì)用戶分配或移除角色;哪些用戶屬于哪個(gè)角色. 在本文,我們將考察ASP.NET 2.0的role service.我們最開始將看如何在網(wǎng)站里建立并配置roles service,以及如何基于認(rèn)證規(guī)則來使用roles. 此外,我們看如何編程來處理roles service,以及如何使用LoginView Web控件,根據(jù)用戶的角色顯示信息. 先前準(zhǔn)備 為使你的website支持角色,你的網(wǎng)站首先要有用戶帳戶,這些帳戶要么 由SqlMembershipProvider存儲(chǔ)在數(shù)據(jù)庫里;要么存儲(chǔ)在其它的數(shù)據(jù)庫里. 而role只是一個(gè)概念,將role分給具體的用戶. 設(shè)置你的Website支持Role 和membership service一樣,roles service也是使用provider模式,只是ASP.NET 2.0有3個(gè)role providers: 1.SqlRoleProvider(默認(rèn)的)—將role信息存儲(chǔ)在一個(gè)SQL Server數(shù)據(jù)庫里.如果你使用SqlMembershipProvider的話,也可以用它來處理roles.具體來說,roles service使用2個(gè)表:aspnet_Roles表用來為系統(tǒng)里的每一個(gè)role生成一條記錄;另一個(gè)是aspnet_UsersInRoles表,該表將aspnet_Users表與aspnet_Roles表里的roles聯(lián)系起來. 2.WindowsTokenRoleProvider—獲得Windows用戶的族群信息.如果你是由Windows authentication登錄的授權(quán)用戶,那么該provider允許你查看用戶所在組的情況 3.AuthorizationStoreRoleProvider—由授權(quán)管理策略提供role信息,比如Active Directory. 本文將只對(duì)SqlRoleProvider provider進(jìn)行考察,為了使用該provider,我們必須創(chuàng)建相應(yīng)的數(shù)據(jù)庫表.就像我們?cè)赑art 1探討的那樣,有2種方式: 1.通過ASP.NET SQL Server注冊(cè)工具(aspnet_regsql.exe)——該工具允許你將必需的數(shù)據(jù)庫表、視圖、存儲(chǔ)過程拷貝到指定的SQL Server 2000 或 SQL Server 2005數(shù)據(jù)庫. 2.通過ASP.NET Website管理工具——當(dāng)將認(rèn)證類型選為"From the internet"時(shí),該工具自動(dòng)的調(diào)用aspnet_regsql.exe工具,在App_Data文件夾里的ASPNETDB.mdf數(shù)據(jù)庫里創(chuàng)建相應(yīng)的數(shù)據(jù)表. 假設(shè)你已經(jīng)創(chuàng)建好了必需的數(shù)據(jù)庫表,要激活role service的話,打開ASP.NET Website管理工具,點(diǎn)擊“Security”標(biāo)簽,再點(diǎn)擊"Enable roles"鏈接,如下所示: 在Web.config文件里添加如下的代碼: <roleManager enabled="true" /> 如果你是使用的自己的數(shù)據(jù)庫來存儲(chǔ)SqlMembershipProvider 和 SqlRoleProvider providers的數(shù)據(jù),你需要在<roleManager>元素里指定 一個(gè)provider,像下面這樣: <configuration> <connectionStrings> <add name="MyDB" connectionString="..." /> </connectionStrings> <system.web> ... authentication & authorization settings ... <roleManager enabled="true" defaultProvider="CustomizedRoleProvider"> <providers> <add name="CustomizedRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="MyDB" /> </providers> </roleManager> </system.web> </configuration> 其中,<connectionString>設(shè)置為myDB,其指定的連接字符串連接的數(shù)據(jù)庫里存儲(chǔ)的是與membership 和 role有關(guān)的數(shù)據(jù)庫表.(我們也可以在<roleManager> 和 <providers>元素里添加額外的特性,我們將在后面的文章探討) 管理Roles role service提供了一個(gè)Roles class類,該類包含的方法可用于創(chuàng)建和刪除角色,以及從角色里添加或移除用戶.當(dāng)你希望以編程的方式來完成這些事情的時(shí)候,這是比較有用的.不過我們通常以手工的形式來進(jìn)行操作.我們可以用ASP.NET Website管理工具來完成,一旦一個(gè)角色被激活后,"Enable roles"鏈接就會(huì)變成這2個(gè)鏈接:"Disable roles"和"Create or Manage roles"。點(diǎn)擊后一個(gè)鏈接的話,在接下來的界面里你可以添加新角色或管理、刪除現(xiàn)有的角色. 點(diǎn)擊Manage鏈接的話,你將看到某個(gè)角色下的一系列用戶.類似的,退回到Security標(biāo)簽,選"Manage users"的話,你也可以看到一個(gè)用戶所屬的一系列角色. 基于Role的認(rèn)證 在ASP.NET 1.x版本里,利用Web.config文件里的<authorization>元素,我們可以對(duì)基于URL的認(rèn)證(URL-based authorization),進(jìn)行user和role級(jí)的限制.具體來說,一個(gè)<authorization>元素包含多個(gè)<allow> 和 <deny>元素,以指定一個(gè)文件夾或URL的認(rèn)證角色.默認(rèn)情況下anyone可以訪問一個(gè)URL,因此如果你要進(jìn)行限制的話,你應(yīng)該將<allow> 和 <deny> 元素合理的組合起來. 在2.0版本里,我們可以通過ASP.NET Website管理工具任意的進(jìn)行設(shè)置.(當(dāng)然,如果你愿意的話,也可以手工在Web.config文件添加<authorization>元素)。在管理工具的Security標(biāo)簽,點(diǎn)"Create access rules"鏈接. 這樣在接下來的界面里你可以將authorization設(shè)置為users, user classes(*代表所有的users,?代表匿名users)或者roles(如果系統(tǒng)里有的話).選一個(gè)文件夾應(yīng)用rules,指定user, user class,或 role,然后選擇訪問權(quán)限(Allow 或 Deny) 處理Roles Class類 通過Role class類可以編程的方式以多種方法訪問role service,比如: .CreateRole(roleName):向系統(tǒng)添加新的角色 .DeleteRole(roleName):從系統(tǒng)刪除角色 .AddUserToRole(userName, roleName):向特定角色添加特定的用戶 .IsUserInRole(roleName) / IsUserInRole(userName, roleName):返回true 或 false.判斷當(dāng)前用戶是否是某個(gè)特定角色的一員. .GetAllRoles():返回有關(guān)系統(tǒng)所有的角色的字符串?dāng)?shù)組 .GetRolesForUser() / GetRolesForUser(userName):返回一個(gè)字符串?dāng)?shù)組,要么是當(dāng)前用戶所屬的所有角色,要么是某個(gè)指定用戶所屬的所有角色. 這些方法可以用來在頁面展示系統(tǒng)里所有的角色,或某個(gè)用戶所屬的所有角色,或判斷某個(gè)用戶是否屬于某個(gè)角色.本文結(jié)尾部分的示例有2個(gè)頁面來演示如何使用Roles lass類:一個(gè)是UserList.aspx頁面,它列出了系統(tǒng)的所有用戶以及用戶所屬的角色。另一個(gè)是RoleList.aspx頁面, 它列出了系統(tǒng)所有的角色以及每個(gè)角色所屬的用戶. 在LoginView控件里使用基于角色的代碼 在前面我們總覽了ASP.NET 2.0里的security Web控件.其中一個(gè)是LoginView控件,它有2個(gè)模板:AnonymousTemplate和LoggedInTemplate. 當(dāng)一個(gè)匿名用戶登錄頁面時(shí),該控件將顯示AnonymousTemplate模板里的內(nèi)容;如果是注冊(cè)用戶登錄的話,將顯示LoggedInTemplate模板里的內(nèi)容. LoginView控件也可以包含基于角色的模板,比如向控件添加一個(gè) <RoleGroups>元素,再在里面放一個(gè)<asp:RoleGroup Roles="comma-delimited list of roles">模板,如下: <asp:LoginView ID="LoginView1" runat="server"> <AnonymousTemplate> OMG, you are, like so not logged in! </AnonymousTemplate> <RoleGroups> <asp:RoleGroup Roles="Developer"> <ContentTemplate> Welcome back! You are a Developer, I can tell by your svelte figure and impeccable social skills! </ContentTemplate> </asp:RoleGroup> <asp:RoleGroup Roles="Administrator"> <ContentTemplate> We all bow down to our system adminstrators! </ContentTemplate> </asp:RoleGroup> </RoleGroups> <LoggedInTemplate> You are logged in!! But, wait, you are not a member of any roles. </LoggedInTemplate> </asp:LoginView> 當(dāng)訪問者登錄頁面時(shí),如果有對(duì)應(yīng)其角色的模板,就顯示該模板里的內(nèi)容. 如果你以Developer角色登錄的話,你就會(huì)看到Developer模板的內(nèi)容,而不是LoggedInTemplate模板的內(nèi)容.類似的,如果你屬于Developer 和 Administrator角色, 你將會(huì)看到看到模板列表里第一個(gè)吻合的模板(就本例而言,為Developer) 結(jié)語: 就像我們?cè)诒疚目吹降哪菢樱珹SP.NET 2.0支持roles和membership services 。它們都使用provider model模式。都包含很多方法來執(zhí)行相應(yīng)的任務(wù).都可以通過ASP.NET Website管理工具進(jìn)行配置. 激活了roles功能后,我們一個(gè)通過編程或使用Website管理工具手工的創(chuàng)建角色或向角色賦值.ASP.NET允許基于角色的驗(yàn)證規(guī)則.所以你可以對(duì)各種文件和文件夾設(shè)置訪問權(quán)限.最后,LoginView控件提供了基于角色的模板,那意味著可以根據(jù)角色的不同顯示不同的內(nèi)容. 祝編程快樂! 考察 ASP.NET 2.0的Membership, Roles, and Profile - Part 3 導(dǎo)言: 默認(rèn)情況下,ASP.NET使用的membership 和 roles 分別使用的是SqlMembershipProvider 和 SqlRoleProvider.它們將membership和roles信息存儲(chǔ)在一個(gè)SQL Server數(shù)據(jù)庫里. 具體來說,信息存儲(chǔ)在一個(gè)預(yù)先定義好了的表里,并可以通過一些預(yù)定義的存儲(chǔ)過程來進(jìn)行訪問.為了在你的應(yīng)用程序里通過默認(rèn)的provider來使用membership 或 roles,我們需要將這些預(yù)定義的構(gòu)造應(yīng)用到你的應(yīng)用程序里. 如果你沒有數(shù)據(jù)庫,還好ASP.NET可以在App_Data文件夾里創(chuàng)建一個(gè)SQL Server 2005 Express版本的數(shù)據(jù)庫以包含必需的數(shù)據(jù)結(jié)構(gòu)(schema).開發(fā)者經(jīng)常要面對(duì)這種情況——手動(dòng)將ASP.NET 2.0的 membership和roles特性添加到一個(gè)現(xiàn)有的數(shù)據(jù)模式(data model)。比如,你的應(yīng)用程序目前還不支持membership 或 roles services,但是需要網(wǎng)站的某些部分對(duì)認(rèn)證用戶可見;或?qū)儆谀撤N角色的用戶限制其功能.這時(shí),我們一個(gè)通過the ASP.NET SQL Server注冊(cè)工具(aspnet_regsql.exe)使一個(gè)現(xiàn)有的數(shù)據(jù)庫支持membership 和 roles. 在本文,我們將考察如何用該工具對(duì)SqlMembershipProvider 好 SqlRoleProvider providers應(yīng)用membership 和 roles services.該工具可以通過命令行或圖形界面來運(yùn)行.另外,我們還將看如何對(duì)App_Data文件夾里的現(xiàn)有的SQL Server 2005 Express數(shù)據(jù)庫運(yùn)用該工具. 如Part 1所述,使用ASP.NET Website管理工具(AWAT)可以在App_Data文件夾里創(chuàng)建一個(gè)名為ASPNETDB.MDF的數(shù)據(jù)庫.有可能有這種網(wǎng)站,其有2個(gè)數(shù)據(jù)庫,一個(gè)是ASPNETDB.MDF數(shù)據(jù)庫,一個(gè)是應(yīng)用程序自己使用的數(shù)據(jù)庫.當(dāng)涉及到與membership和roles有關(guān)的查詢時(shí),比如驗(yàn)證用戶的身份,或創(chuàng)建一個(gè)新的用戶帳戶等,就使用ASPNETDB.MDF數(shù)據(jù)庫;而網(wǎng)站頁面依然使用原來的數(shù)據(jù)庫.下面的圖闡明了這種關(guān)系. 最理想的是將與membership相關(guān)的數(shù)據(jù)結(jié)構(gòu)(schema),轉(zhuǎn)移到應(yīng)用程序現(xiàn)有的數(shù)據(jù)庫,所有的查詢都要使用現(xiàn)有的數(shù)據(jù)庫.如下圖: 不過,我們一定要這么做嗎?為什么不能使用2個(gè)數(shù)據(jù)庫,一個(gè)處理membership services另一個(gè)處理現(xiàn)有程序的工作?然而不管怎么樣我依然建議將這2者合并起來. 打個(gè)比方,設(shè)想你有一個(gè)相薄程序,目前只有你才能添加相片。你可以運(yùn)用ASP.NET 2.0的 membership功能,只允許認(rèn)證用戶才能訪問該圖片,另外,你還可以為你或你的配偶創(chuàng)建1到2個(gè)用戶帳戶。在這種情況,將membership schema添加到現(xiàn)有的數(shù)據(jù)庫是比較理想的.另外,如果你允許訪問者創(chuàng)建自己的帳戶,并對(duì)圖片發(fā)表評(píng)論的話,你可以在現(xiàn)有數(shù)據(jù)庫創(chuàng)建一個(gè)Comments表,該表引用aspnet_Users表的一個(gè)外鍵,以便顯示是那個(gè)人發(fā)表的評(píng)論. 將Membership相關(guān)的Schema應(yīng)用到一個(gè)現(xiàn)有的數(shù)據(jù)庫 要完成這個(gè)工作,使用ASP.NET SQL Server注冊(cè)工具(aspnet_regsql.exe)是很容易辦到的.在命令行里導(dǎo)航到%WINDOWS%\Microsoft.NET\Framework\v2.0.50727,再運(yùn)行aspnet_regsql.exe這將開啟ASP.NET SQL Server Setup Wizard向?qū)?,在向?qū)Ю锬阋礊閍pplication services配置一個(gè)SQL Server數(shù)據(jù)庫(也就是添加membership相關(guān)的schema),要么從數(shù)據(jù)庫轉(zhuǎn)移出schema,如下圖: 在接下來的界面,你要選擇一個(gè)數(shù)據(jù)庫來添加或(轉(zhuǎn)移入)與membership相關(guān)的schema.如下圖: 指定了數(shù)據(jù)庫后,點(diǎn)Next預(yù)覽將要做的改動(dòng),預(yù)覽完后點(diǎn)Next完成schema的配置。這將為membership providers添加必要的表、視圖、存儲(chǔ)過程. ASP.NET SQL Server注冊(cè)工具所要做的是將%WINDOWS%\Microsoft.NET\Framework\v2.0.50727\InstallCommon.sql創(chuàng)建的腳本稍加修改后運(yùn)行.而%WINDOWS%\Microsoft.NET\Framework\v2.0.50727\InstallCommon.sql的腳本將嘗試連接名為aspnetdb的數(shù)據(jù)庫.它將建立所有與membership相關(guān)的服務(wù): Membership, Roles, Profile, Personalization等等.更多的腳本見%WINDOWS%\Microsoft.NET\Framework\v2.0.50727\目錄. 腳本嘗試連接具體的數(shù)據(jù)庫(要么是aspnetdb數(shù)據(jù)庫,要么是在向?qū)Ю镏付ǖ臄?shù)據(jù)庫)。如果它不能在server's sysdatabases table表里找到該數(shù)據(jù)庫的話, 那么就將根據(jù)指定的名稱創(chuàng)建數(shù)據(jù)庫,再添加各種表、視圖、存儲(chǔ)過程. 從命令行運(yùn)行ASP.NET SQL Server注冊(cè)工具 除了圖形界面以外,我們也可以從命令行調(diào)用ASP.NET SQL Server注冊(cè)工具。導(dǎo)航到 %WINDOWS%\Microsoft.NET\Framework\v2.0.50727,運(yùn)行: -- To use Windows Authentication (i.e., a "trusted connection"), use: aspnet_regsql.exe -S <server> -E -d <database> -A all -- To use SQL Server credentials (a UserID and Password), use: aspnet_regsql.exe -S <server> -U <login id> -P <password> -d <database> -A all 其中-A all將安裝與membership相關(guān)的所有服務(wù)。你也可以用-A list來安裝某個(gè)具體的membership特性,比如-A mr將安裝membership和roles.運(yùn)行aspnet_regsql.exe -? 將查看所有選項(xiàng)的全部清單. 如果你的應(yīng)用程序現(xiàn)有的數(shù)據(jù)庫為App_Data文件夾里的一個(gè)SQL Server 2005 Express Edition版本的數(shù)據(jù)庫.你也許想知道如何正確的通過ASP.NET SQL Server注冊(cè)工具來訪問它. 那么你如何處理server name, credentials,以及database name呢?首先聲明我不是專家,下面的意見為我自己認(rèn)識(shí)到的: .Server name為localhost\InstanceName——默認(rèn)時(shí)SQL Server 2005 Express Edition的InstanceName為SQLExpress,因此使用的Server name就為localhost\SQLExpress. .SQL Server 2005 Express Edition默認(rèn)安裝為接受Windows Authentication.所以將authentication項(xiàng)設(shè)置為Windows Authentication. .database name有點(diǎn)棘手.就我所知,當(dāng)在App_Data數(shù)據(jù)庫里創(chuàng)建一個(gè)SQL Server 2005 Express Edition數(shù)據(jù)庫時(shí),那么數(shù)據(jù)庫名為其完整的路徑,比如如果數(shù)據(jù)庫完整路徑為C:\Home\Websites\PhotoAlbum\App_Data\Photos.mdf,那么其數(shù)據(jù)庫名也為C:\Home\Websites\PhotoAlbum\App_Data\Photos.mdf. 不過我們需要將其添加為SQL Server 2005 Express Edition實(shí)例,以便于ASP.NET SQL Server注冊(cè)工具引用. 對(duì)現(xiàn)有的SQL Server 2005 Express Edition數(shù)據(jù)庫提供一個(gè)名稱,使用免費(fèi)下載的SQL Server 2005 Management Studio Express Edition來做是很容易的. 如果你的電腦里安裝的是SQL Server 2005 Standard Edition或更高版本的話,那么你也已經(jīng)裝好了SQL Server 2005的Management Studio 。那么你就無法再安裝Management Studio的Express Edition版本了. 如果你不能在連接屏幕通過:localhost\SQLExpress (或者你安裝的其它目錄)來連接到SQL Server 2005 Express Edition數(shù)據(jù)庫實(shí)例的話, 那么在Management Studio里,連接到一個(gè)database server后,在 Databases文件夾上點(diǎn)擊右鍵,選“Attach”,來分配數(shù)據(jù)庫.你然后可以選擇需要的數(shù)據(jù)庫。該數(shù)據(jù)庫的名稱為初始(original)創(chuàng)建時(shí)的完整路徑名.我說“初始”是因?yàn)槿绻銓⒃摂?shù)據(jù)庫文件從一個(gè)目錄移動(dòng)到另一個(gè)目錄的話,它的名稱依然是最初創(chuàng)建時(shí)的完整路徑.要改變數(shù)據(jù)庫的名稱,可以點(diǎn)“Script” 按鈕,再重命名。還一個(gè)方法,在Management Studio里,在該數(shù)據(jù)庫上右鍵單擊,選“Rename”. 完成添加后,我們就可以用ASP.NET SQL Server注冊(cè)工具來引用它.如果你不想用Management Studio來進(jìn)行添加,那么請(qǐng)參閱文章《Working With SQL Server 2005 Express Databases》(http:///sowblog/posts/5480.aspx) 讓Membership Providers使用應(yīng)用程序現(xiàn)有的數(shù)據(jù)庫 當(dāng)將與membership相關(guān)的schema轉(zhuǎn)移到應(yīng)用程序現(xiàn)有的數(shù)據(jù)庫后,我們將從現(xiàn)有數(shù)據(jù)庫進(jìn)行membership相關(guān)的查詢,而不是從ASPNETDB.MDF數(shù)據(jù)庫.然而SQL Server Membership的幾個(gè)provider——SqlMembershipProvider, SqlRoleProvider, SqlProfileProvider等都默認(rèn)使用ASPNETDB.MDF數(shù)據(jù)庫.為此,我們要在Web.config文件里添加我們自己的provider實(shí)例以使用現(xiàn)有的數(shù)據(jù)庫,并作為默認(rèn)的Membership providers. 就像在Part 1探討的那樣,我們可以在Web.config文件對(duì)provider信息進(jìn)行配置,使membership providers和roles providers調(diào)用現(xiàn)有的數(shù)據(jù)庫而不是ASPNETDB.MDF,如下: <configuration> <connectionStrings> <add name="MyDB" connectionString="..." /> </connectionStrings> <system.web> ... authentication & authorization settings ... <roleManager enabled="true" defaultProvider="CustomizedRoleProvider"> <providers> <add name="CustomizedRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="MyDB" /> </providers> </roleManager> <membership defaultProvider="CustomizedMembershipProvider"> <providers> <add name="CustomizedMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MyDB" /> </providers> </membership> </system.web> </configuration> 以上設(shè)置為membership 和 roles systems創(chuàng)建了一個(gè)用戶自定義providers,用到的連接字符串為“MyDB”,它指向了應(yīng)用程序里現(xiàn)有的數(shù)據(jù)庫. 結(jié)語: 當(dāng)對(duì)程序啟動(dòng)membership支持后,我們需要將membership schema應(yīng)用到一個(gè)現(xiàn)有的數(shù)據(jù)庫上,該工作可以通過ASP.NET SQL Server注冊(cè)工具來完成。完成之后,最后一步是對(duì)provider進(jìn)行定制,以使用現(xiàn)有的數(shù)據(jù)庫而不是默認(rèn)的ASPNETDB.MDF 祝編程快樂! 考察 ASP.NET 2.0的Membership, Roles, and Profile - Part 4 導(dǎo)言: ASP.NET 2.0 的Membership class類有一個(gè)ValidateUser(userName, password)方法,返回一個(gè)布爾值。用于驗(yàn)證用戶的登錄信息是否有效.該方法被Login Web控件自動(dòng)調(diào)用,當(dāng)然如果需要的話也可以通過編程調(diào)用.在Membership system,有幾種情況,用戶無法通過驗(yàn)證: 1.username無效 2.username有效,但password無效 3.username和password都有效,但 .用戶可能還未被核準(zhǔn)(approved) .用戶被鎖定(locked out),原因可能是用戶用無效密碼登錄了好幾次( 默認(rèn)為5次) 不幸的是,如果登錄失敗,ValidateUser(userName, password)方法只會(huì)返回一個(gè)False,而不包含為什么登錄失敗的具體原因.對(duì)Login控件而言,當(dāng)ValidateUser(userName, password)方法返回False的同時(shí),默認(rèn)還會(huì)顯示一個(gè)消息:"Your login attempt was not successful. Please try again." 如果是這種情況,用戶被鎖定(locked out)或帳戶還未被核準(zhǔn)——此時(shí)他們的username和password都沒問題,顯示這樣的消息就讓用戶感到困惑了.在本文,我們將在登錄過程中添加額外的反饋信息,以避免這種尷尬的情況. 審核和鎖定(Locked Out)用戶帳戶 ASP.NET 2.0 Membership system里的用戶帳戶,我們可以利用Membership 和 MembershipUser classes類以編程的方式訪問并進(jìn)行修改.Membership包含一系列的方法以返回某一個(gè)或所有用戶的信息、更新某個(gè)用戶的信息等;而MembershipUser class類包含的屬性描述了某個(gè)用戶的具體情況(UserName, Email, LastLoggedOnDate等等). Membership system可以將用戶帳戶標(biāo)記為inactive(未審批)和locked out.當(dāng)創(chuàng)建一個(gè)新賬號(hào)時(shí),默認(rèn)是被審批的.然后在某些情況下,你可能希望讓管理員手動(dòng)批準(zhǔn)新帳戶,或者是其它自動(dòng)方式來審批(比如,點(diǎn)擊一個(gè)確認(rèn)連接發(fā)送郵件).不管是哪種方式,剛創(chuàng)建的用戶都會(huì)被標(biāo)記為inactive.這樣,該用戶就無法登錄網(wǎng)站,因?yàn)閂alidateUser(userName, password)總是返回False,無論用戶名和密碼是否正確. 由于驗(yàn)證過程是通過一個(gè)基于窗體的構(gòu)架(forms-based scheme),只是簡(jiǎn)單的通過一個(gè)HTTP request來發(fā)送用戶認(rèn)證(credential).這樣,某個(gè)攻擊者便可以嘗試破解某個(gè)用戶帳戶,方法是編寫腳本遍歷一個(gè)通用密碼字典(a dictionary of common passwords),對(duì)某個(gè)特定的帳戶,用字典里的所有密碼嘗試進(jìn)行登錄.為阻止這種攻擊,如果在特定時(shí)間段內(nèi)用無效密碼登錄了特定次數(shù)后,Membership system自動(dòng)將某個(gè)用戶鎖定.默認(rèn)設(shè)置為在10分鐘內(nèi)(a ten minute window)無效登錄5次.當(dāng)然,我們可以在Web.config文件里對(duì)其進(jìn)行定制.和未審批用戶一樣,被鎖定的用戶同樣不能登錄網(wǎng)站,無論其用戶名和密碼是否正確.為了對(duì)用戶進(jìn)行解鎖,需要調(diào)用MembershipUser class類的UnlockUser()方法.當(dāng)從Login Web控件登錄失敗時(shí),我們可以對(duì)登錄頁面進(jìn)行定制以顯示更多恰當(dāng)?shù)南? 登錄失敗時(shí)顯示更有價(jià)值的消息 當(dāng)用戶用Login Web控件進(jìn)行登錄時(shí)就會(huì)觸發(fā)其LoginError事件.該事件不會(huì)傳遞指明登錄失敗的任何信息.不過,我們可以通過Login控件的UserName 和 Password屬性來獲取該用戶的username 和 password.我們可以調(diào)用Membership.GetUser(userName)方法來獲取用戶帳戶的信息. 該方法返回一個(gè)MembershipUser對(duì)象,我們可以檢查其IsApproved 和 IsLockedOut屬性來判定為何用戶的認(rèn)證被認(rèn)為是無效的. 下面的代碼顯示了如何來實(shí)現(xiàn)它.最終的幫助信息顯示在一個(gè)名為L(zhǎng)oginErrorDetails的Label Web控件里.你在本文的下載代碼里可看到Login頁面的完整代碼和聲明. Protected Sub Login1_LoginError(ByVal sender As Object, ByVal e As System.EventArgs) Handles Login1.LoginError 'There was a problem logging in the user 'See if this user exists in the database Dim userInfo As MembershipUser = Membership.GetUser(Login1.UserName) If userInfo Is Nothing Then 'The user entered an invalid username... LoginErrorDetails.Text = "There is no user in the database with the username " & Login1.UserName Else 'See if the user is locked out or not approved If Not userInfo.IsApproved Then LoginErrorDetails.Text = "Your account has not yet been approved by the site's administrators. Please try again later..." ElseIf userInfo.IsLockedOut Then LoginErrorDetails.Text = "Your account has been locked out because of a maximum number of incorrect login attempts. You will NOT be able to login until you contact a site administrator and have your account unlocked." Else 'The password was incorrect (don't show anything, the Login control already describes the problem) LoginErrorDetails.Text = String.Empty End If End If End Sub 使用上面的代碼,用戶登錄失敗后將看到更有意義的消息.下面的截屏顯示的是以Bruce(其帳戶已被鎖定)和Alfred(其帳戶還未被審批)的名字登錄的情形.沒有上述的事件處理器,他們都只能看到標(biāo)準(zhǔn)的"Your login attempt was not successful. Please try again." 提示消息.很明顯,他們將感到很迷惑,無法意識(shí)到其帳戶已經(jīng)被鎖定或未被審批. 由于ASP.NET 2.0 Membership system可以鎖定用戶帳戶并不再接受登錄.如此情況,可提供一個(gè)快速反饋,看哪些用戶被鎖定,哪些用戶未被審批.要捕獲這些信息,我在membership數(shù)據(jù)庫里創(chuàng)建了一個(gè)InvalidCredentialsLog表,其構(gòu)架如下: Membership system包含一個(gè)ApplicationID,它允許多個(gè)應(yīng)用程序在一個(gè)數(shù)據(jù)庫里存儲(chǔ)各自的用戶帳戶.理想情況下,該表應(yīng)包含ApplicationID,并只報(bào)告當(dāng)前應(yīng)用程序的那些無效認(rèn)證(假定你用一個(gè)單一的membership store來應(yīng)對(duì)多個(gè)應(yīng)用程序).我將其作為練習(xí)留給讀者. 接下來,我將創(chuàng)建一個(gè)存儲(chǔ)過程——InvalidCredentialsLog_Insert,它存儲(chǔ)用戶的username, password,和IP address.它檢查當(dāng)前username是否與aspnet_Users表里的用戶匹配,若是,則提取用戶的IsApproved 和 IsLockedOut列的值,然后添加到InvalidCredentialsLog_Insert表. 當(dāng)用戶無效登錄時(shí),需要調(diào)用該存儲(chǔ)過程,并傳入用戶信息.為此,我創(chuàng)建了一個(gè)ID為InvalidCredentialsLogDataSource的SqlDataSource控件,設(shè)置其調(diào)用該存儲(chǔ)過程,然后我們對(duì)Login Web控件的LoginError事件處理器進(jìn)行擴(kuò)充,為該存儲(chǔ)過程設(shè)置參數(shù)并調(diào)用它: Protected Sub Login1_LoginError(ByVal sender As Object, ByVal e As System.EventArgs) Handles Login1.LoginError 'Set the parameters for InvalidCredentialsLogDataSource InvalidCredentialsLogDataSource.InsertParameters("ApplicationName").DefaultValue = Membership.ApplicationName InvalidCredentialsLogDataSource.InsertParameters("UserName").DefaultValue = Login1.UserName InvalidCredentialsLogDataSource.InsertParameters("IPAddress").DefaultValue = Request.UserHostAddress 'The password is only supplied if the user enters an invalid username or invalid password - set it to Nothing, by default InvalidCredentialsLogDataSource.InsertParameters("Password").DefaultValue = Nothing 'There was a problem logging in the user 'See if this user exists in the database Dim userInfo As MembershipUser = Membership.GetUser(Login1.UserName) If userInfo Is Nothing Then 'The user entered an invalid username... LoginErrorDetails.Text = "There is no user in the database with the username " & Login1.UserName 'The password is only supplied if the user enters an invalid username or invalid password InvalidCredentialsLogDataSource.InsertParameters("Password").DefaultValue = Login1.Password Else 'See if the user is locked out or not approved If Not userInfo.IsApproved Then LoginErrorDetails.Text = "Your account has not yet been approved by the site's administrators. Please try again later..." ElseIf userInfo.IsLockedOut Then LoginErrorDetails.Text = "Your account has been locked out because of a maximum number of incorrect login attempts. You will NOT be able to login until you contact a site administrator and have your account unlocked." Else 'The password was incorrect (don't show anything, the Login control already describes the problem) LoginErrorDetails.Text = String.Empty 'The password is only supplied if the user enters an invalid username or invalid password InvalidCredentialsLogDataSource.InsertParameters("Password").DefaultValue = Login1.Password End If End If 'Add a new record to the InvalidCredentialsLog table InvalidCredentialsLogDataSource.Insert() End Sub 此外,我還構(gòu)建了一個(gè)報(bào)告頁面,在一個(gè)可分頁、排序的GridView控件.如下所示,該頁面也包含在下載內(nèi)容里 就一般的網(wǎng)站而言,該InvalidCredentialsLog表可能會(huì)很大。我們可以采取一些措施來將超過某個(gè)時(shí)間的老的記錄刪除(比如3個(gè)月前的記錄)。上面顯示出來的報(bào)告很簡(jiǎn)單,對(duì)大數(shù)據(jù)的結(jié)果也沒有進(jìn)行優(yōu)化處理.它使用默認(rèn)的分頁,從數(shù)據(jù)庫將每個(gè)頁面的數(shù)據(jù)都檢索出來。如果想自定義分頁,僅僅檢索當(dāng)前頁面所需要的記錄,請(qǐng)參閱文章《Custom Paging in ASP.NET 2.0 with SQL Server 2005》(http://aspnet./articles/031506-1.aspx) 結(jié)語: 本文,我們看如何對(duì)登錄過程進(jìn)行優(yōu)化,當(dāng)被鎖定或未為被審批的用戶登錄時(shí)顯示更有意義的信息.這都要感謝Membership API,它可以通過編程、顯式地(通過數(shù)據(jù)源控件)、或Web控件(比如Login Web控件)來訪問.在下載代碼里有一個(gè)Admin頁面,它用一個(gè)GridView控件將系統(tǒng)的所有用戶列出來,允許用戶查看其審批狀態(tài)、將鎖定的用戶解鎖、查看某人用戶是否是Administrator角色(只有Administrator角色才能查看與管理相關(guān)的頁面) 祝編程快樂! 考察ASP.NET 2.0中的Membership, Roles, and Profile - Part 5 導(dǎo)言: 我們知道ASP.NET 2.0通過membership, roles,profile systems來創(chuàng)建和管理用戶帳戶。要為用戶提供登錄頁面的話,我們只需要拖一個(gè)Login Web控件到頁面即可.但如果我們想做一些用戶定制呢?我們可以重新配置Login控件,再另外添加一些內(nèi)容;或者出除了用戶名和密碼外,我們還希望用戶提供email地址等,或者包含一個(gè)CAPTCHA(一些box,其text的背景為圖片).可以通過多種方式來對(duì)Login Web控件進(jìn)行定制.比如,是否顯示"Remember me next time", 顏色、字體等設(shè)置;我們還可以將控件轉(zhuǎn)換成一個(gè)模板(template);我們還可以為Authenticate event事件創(chuàng)建處理器,自定義認(rèn)證邏輯,甚至使用CAPTCHA作為認(rèn)證的一部分。 本文,我們將考察如何通過Login控件的屬性、通過模板來對(duì)其進(jìn)行定制,通過Authentication事件處理器定制認(rèn)證邏輯. 通過屬性定制Login控件 首先我們要?jiǎng)?chuàng)建一個(gè)登錄頁面,如果用戶嘗試訪問其未被授權(quán)的頁面或點(diǎn)擊LoginStatus控件的Login按鈕時(shí)就會(huì)自動(dòng)的重新定位到該頁面。默認(rèn)情況下,該頁面必須命名為L(zhǎng)ogin.aspx,并放在根目錄下.當(dāng)然如果你喜歡的話也可以使用其它的登錄URL,但是你需要在Web.config文件里的<authentication>節(jié)點(diǎn)里更新<forms>元素: <?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> ... <authentication mode="Forms"> <forms loginUrl="LoginPath" /> </authentication> ... </system.web> </configuration> 從工具欄拖該Login控件到我們創(chuàng)建的登錄頁面上,如下圖所示,Login控件默認(rèn)包含如下的內(nèi)容: . 一個(gè)User Name TextBox . 一個(gè)Password TextBox . 一個(gè)"Remember me next time" CheckBox . 一個(gè)"Log In" Button 此外,Login控件還有RequiredFieldValidators控件,以確保用戶輸入的User Name和Password不為空。另外,還有一個(gè)Literal控件用來顯示Login控件的FailureText屬性的值. 可以通過各種與style相關(guān)的屬性來美好Login控件的外觀。比如Font, BackColor, Width, Height等等.另外還可以通過TextBoxStyle, CheckBoxStyle,和LoginButtonStyle來設(shè)置Login控件內(nèi)部的TextBoxes, CheckBox,和Button Web控件. 我們還可以改變其屬性。比如,想將 "User Name:"文本換成別的嗎?改動(dòng)UserNameLabelText屬性即可;想在添加說明嗎?在InstructionText屬性設(shè)置即可;通過LoginButtonText屬性改變"Log In" Button的文本.通過HelpPageText 和 HelpPageUrl屬性來添加一個(gè)定位到幫助頁面的鏈接.而Orientation屬性決定了Login控件如何布局.下圖以及下載內(nèi)容包含的Login控件演示了如何改變相關(guān)屬性的值來改變其外觀。 以上只是進(jìn)行了一定程度的定制,要想進(jìn)行更大程度的定制,我們必須將其轉(zhuǎn)變成一個(gè)模板。為此,切換到設(shè)計(jì)模式,在智能標(biāo)簽里點(diǎn)"Convert to Template" 項(xiàng)。這將在Login控件的聲明代碼里添加一個(gè) <LayoutTemplate>,包含一個(gè)HTML <table> ,其構(gòu)造復(fù)制了默認(rèn)的Login控件的布局.你想怎么調(diào)整布局都行,包括添加額外的內(nèi)容和Web控件. 有一點(diǎn)很重要要記住,在模板里的某些登錄控件必須保留其原有的ID值。具體來說,<LayoutTemplate>里有2個(gè)控件的ID值為UserName和 Password,它們構(gòu)成了ITextControl界面.另外,你可以使用你個(gè)人的自定義服務(wù)器控件或User Control,只要它們也可以執(zhí)行這種界面.另外,你需要一個(gè)Button, LinkButton, 或ImageButton,其CommandName要設(shè)置為L(zhǎng)ogin控件的LoginButtonCommandName靜態(tài)域(默認(rèn)為"Login"),但其ID卻可以是任意值.Login控件轉(zhuǎn)變成模板時(shí)自動(dòng)生成的其它控件都是可選的. 下面的聲明代碼是我對(duì)Login控件的<LayoutTemplate>調(diào)整后的布局: <asp:Login ID="Login1" runat="server" BackColor="#F7F7DE" BorderColor="#CCCC99" BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana" Font-Size="10pt" RememberMeSet="True"> <TitleTextStyle BackColor="#6B696B" Font-Bold="True" ForeColor="White" /> <LayoutTemplate> <table border="0" cellpadding="1" cellspacing="0" style="border-collapse: collapse"> <tr> <td align="center" rowspan="3" style="padding:15px; font-weight: bold; color: white; background-color: #6b696b"> Log In </td> <td style="width:8px;"> </td> <td align="right"> <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName">User Name:</asp:Label></td> <td> <asp:TextBox ID="UserName" runat="server" TabIndex="1"></asp:TextBox> <asp:RequiredFieldValidator ID="UserNameRequired" runat="server" ControlToValidate="UserName" ErrorMessage="User Name is required." ToolTip="User Name is required." ValidationGroup="Login1">*</asp:RequiredFieldValidator> </td> <td align="center" rowspan="3" style="padding:15px;"> <asp:Button ID="LoginButton" runat="server" CommandName="Login" Text="Log In" ValidationGroup="Login1" TabIndex="4" /> </td> </tr> <tr> <td style="width:8px;"> </td> <td align="right"> <asp:Label ID="PasswordLabel" runat="server" AssociatedControlID="Password">Password:</asp:Label></td> <td> <asp:TextBox ID="Password" runat="server" TextMode="Password" TabIndex="2"></asp:TextBox> <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password" ErrorMessage="Password is required." ToolTip="Password is required." ValidationGroup="Login1">*</asp:RequiredFieldValidator> </td> </tr> <tr> <td style="width:8px;"> </td> <td colspan="2"> <asp:CheckBox ID="RememberMe" runat="server" Text="Remember me next time." TabIndex="3" /> </td> </tr> </table> <asp:ValidationSummary ID="ValidationSummary1" runat="server" ShowMessageBox="True" ValidationGroup="Login1" ShowSummary="False" /> </LayoutTemplate> </asp:Login> 心細(xì)的讀者可能已經(jīng)注意到上面的布局忽略了FailureText Literal控件,該控件在用戶登錄失敗時(shí)顯示Login控件FailureText屬性的值。我決定在一個(gè)客戶端alert box里顯示該文本。為此,我將為L(zhǎng)ogin控件的 LoginError事件創(chuàng)建處理器,編寫必要的JavaScript來展示該alert box。(在Part 4我們探討過該事件) Protected Sub Login1_LoginError(ByVal sender As Object, ByVal e As System.EventArgs) Handles Login1.LoginError 'Display the failure message in a client-side alert box ClientScript.RegisterStartupScript(Me.GetType(), "LoginError", _ String.Format("alert('{0}');", Login1.FailureText.Replace("'", "\'")), True) End Sub 最后,請(qǐng)注意<table>標(biāo)簽后的ValidationSummary控件的內(nèi)容,我將ShowSummary 和 ShowMessageBox屬性做上述設(shè)置后,一旦輸入有誤(也就是說沒有輸入username 或password)時(shí)將顯示一個(gè)客戶端的alert box.下面的一個(gè)圖,alert box顯示用戶必須輸入username;而第二個(gè)圖片,用戶嘗試登錄,但輸入有誤. 定制認(rèn)證邏輯 當(dāng)用戶輸入完并點(diǎn)擊"Log In"按鈕時(shí),緊接著發(fā)生如下的步驟: 1.發(fā)生頁面回傳 2.Login控件的LoggingIn事件觸發(fā) 3.Login控件的Authenticate事件觸發(fā);它調(diào)用一個(gè)事件處理器以執(zhí)行必要的邏輯,判斷用戶認(rèn)證是否有效,若有 效則該事件處理器將傳入的AuthenticateEventArgs對(duì)象的Authenticated屬性設(shè)為True. 4.如果用戶認(rèn)證失敗將引發(fā)LoginError事件,反之將引發(fā)LoggedIn事件 默認(rèn),Login控件在內(nèi)部處理Authenticate事件,通過調(diào)用Membership class類的ValidateUser(username, password)方法來進(jìn)行驗(yàn)證。然而,我們可以對(duì)Login控件使用的驗(yàn)證邏輯進(jìn)行定制,我們可以自己創(chuàng)建該事件的事件處理器,如果通過驗(yàn)證就將e.Authenticated屬性設(shè)為True;而未通過就設(shè)為False. 本例,我們不僅要驗(yàn)證username 和 password,而且還有其email地址,以及一個(gè)CAPTCHA.我們知道CAPTCHA是一種人可以感知(而機(jī)器人程序無法感知)的技術(shù).CAPTCHA通常為在一個(gè)圖片上顯示一些扭曲的文本,讓用戶輸入這些文本.計(jì)算機(jī)程序不能分析該圖片以及破解其中的文本,而只有人才可以輕松的做到。我用到的該CAPTCHA是eff Atwood的免費(fèi)且優(yōu)秀ASP.NET CAPTCHA server control控件. 要?jiǎng)?chuàng)建一個(gè)用戶自定義驗(yàn)證邏輯示例,我們先將一個(gè)標(biāo)準(zhǔn)的Login控件轉(zhuǎn)變?yōu)橐粋€(gè)模板,并添加一個(gè)名為Email的TextBox(附帶一個(gè)RequiredFieldValidator控件),以及一個(gè)Jeff的CAPTCHA控件: <asp:Login ID="Login1" ...> <LayoutTemplate> <table border="0" cellpadding="1" cellspacing="0" style="border-collapse: collapse"> <tr> <td align="center" rowspan="5" style="padding:15px; font-weight: bold; color: white; background-color: #6b696b"> Log In </td> <td style="width:8px;"> </td> <td align="right"> <asp:Label Font-Bold="True" ID="UserNameLabel" runat="server" AssociatedControlID="UserName">User Name:</asp:Label></td> <td> <asp:TextBox ID="UserName" runat="server" TabIndex="1"></asp:TextBox> <asp:RequiredFieldValidator ID="UserNameRequired" runat="server" ControlToValidate="UserName" ErrorMessage="User Name is required." ToolTip="User Name is required." ValidationGroup="Login1">*</asp:RequiredFieldValidator> </td> <td align="center" rowspan="5" style="padding:15px;"> <asp:Button ID="LoginButton" runat="server" CommandName="Login" Text="Log In" ValidationGroup="Login1" TabIndex="5" /> </td> </tr> <tr> <td style="width:8px;"> </td> <td align="right"> <asp:Label Font-Bold="True" ID="PasswordLabel" runat="server" AssociatedControlID="Password">Password:</asp:Label></td> <td> <asp:TextBox ID="Password" runat="server" TextMode="Password" TabIndex="2"></asp:TextBox> <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password" ErrorMessage="Password is required." ToolTip="Password is required." ValidationGroup="Login1">*</asp:RequiredFieldValidator> </td> </tr> <tr> <td style="width:8px;"> </td> <td align="right"> <asp:Label Font-Bold="True" ID="EmailLabel" runat="server" AssociatedControlID="Email">Email:</asp:Label></td> <td> <asp:TextBox ID="Email" runat="server" TabIndex="3"></asp:TextBox> <asp:RequiredFieldValidator ID="EmailRequired" runat="server" ControlToValidate="Email" ErrorMessage="Email is required." ToolTip="Email is required." ValidationGroup="Login1">*</asp:RequiredFieldValidator> </td> </tr> <tr> <td style="width:8px;"> </td> <td align="right"> <b>Verification:</b> </td> <td> <cc1:CaptchaControl id="CAPTCHA" runat="server" ShowSubmitButton="False" TabIndex="3" LayoutStyle="Vertical"></cc1:CaptchaControl> </td> </tr> <tr> <td style="width:8px;"> </td> <td colspan="2"> <asp:CheckBox ID="RememberMe" runat="server" Text="Remember me next time." TabIndex="4" /> </td> </tr> </table> <asp:ValidationSummary ID="ValidationSummary1" runat="server" ShowMessageBox="True" ValidationGroup="Login1" ShowSummary="False" /> </LayoutTemplate> </asp:Login> 接下來,我們將為Authenticate事件創(chuàng)建一個(gè)事件處理器.我們先檢查CAPTCHA是否有效,再用Membership.ValidateUser方法來確保用戶的username 和 password是有效的;再調(diào)用Membership.GetUser(username)方法,將Email屬性與用戶提供的做對(duì)比;如果有任何一項(xiàng)出錯(cuò),則將 e.Authenticated設(shè)為False,反之則設(shè)為True. 我對(duì)Login控件的FailureText屬性進(jìn)行了更新,顯示用戶無法登錄的更具體的信息. 注意我們?cè)?lt;LayoutTemplate>里用LoginControl.FindControl("ID")方法來訪問控件(比如Email TextBox 或 CAPTCHA控件). Protected Sub Login1_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles Login1.Authenticate 'We need to determine if the user is authenticated and set e.Authenticated accordingly 'Get the values entered by the user Dim loginUsername As String = Login1.UserName Dim loginPassword As String = Login1.Password 'To get a custom Web control, must use FindControl Dim loginEmail As String = CType(Login1.FindControl("Email"), TextBox).Text Dim loginCAPTCHA As WebControlCaptcha.CaptchaControl = CType(Login1.FindControl("CAPTCHA"), WebControlCaptcha.CaptchaControl) 'First, check if CAPTCHA matches up If Not loginCAPTCHA.UserValidated Then 'CAPTCHA invalid Login1.FailureText = "The code you entered did not match up with the image provided; please try again with this new image." e.Authenticated = False Else 'Next, determine if the user's username/password are valid If Membership.ValidateUser(loginUsername, loginPassword) Then 'See if email is valid Dim userInfo As MembershipUser = Membership.GetUser(loginUsername) If String.Compare(userInfo.Email, loginEmail, True) <> 0 Then 'Email doesn't match up e.Authenticated = False Login1.FailureText = "The email address you provided is not the email address on file." Else 'Only set e.Authenticated to True if ALL checks pass e.Authenticated = True End If Else e.Authenticated = False Login1.FailureText = "Your username and/or password are invalid." End If End If End Sub 做完這些修改后,該Login控件現(xiàn)在包含了用戶的email以及一個(gè)CAPTCHA,如下所示,只有當(dāng)用戶提供正確的username, password, email address,CAPTCHA后才能正確登錄. 結(jié)語: 本文,我們看到了如何通過改變Login控件的配置或?qū)⑵滢D(zhuǎn)變?yōu)橐粋€(gè)模板,來定制其外觀和布局.當(dāng)轉(zhuǎn)變?yōu)槟0搴笪覀兛梢蕴砑宇~外的Web控件,比如一個(gè)CAPTCHA.再為L(zhǎng)ogin控件的Authenticate事件創(chuàng)建一個(gè)事件處理器,我們可以自定義驗(yàn)證邏輯. 祝編程快樂! 附錄: 名詞解釋:CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart ,全自動(dòng)區(qū)分計(jì)算機(jī)和人類的圖靈測(cè)試) CAPTCHA ——用以區(qū)分計(jì)算機(jī)和人類,在人機(jī)差別非常小的網(wǎng)絡(luò)上非常有效。它會(huì)生成一個(gè)隨機(jī)的圖片顯示給用戶。這個(gè)圖片含有一個(gè)不容易被計(jì)算機(jī)識(shí)別(OCR)的字符串,同時(shí)這個(gè)字符串在頁面的代碼及其他計(jì)算機(jī)可以獲取的地方被使用。如果表單提交的時(shí)候并不含有正確的字符串,系統(tǒng)就能夠確信輸入人員錄入錯(cuò)誤或者不是一個(gè)真正的人在進(jìn)行錄入。 沿著上述思路發(fā)展,除了圖象外,目前又出現(xiàn)了語音形式的驗(yàn)證方法。 考察ASP.NET 2.0的Membership, Roles,Profile - Part 6 導(dǎo)言: 除了用戶帳戶的username, passsword, email, security question和 answer等,在實(shí)際的程序中我們還可能添加額外的信息,比如我們可能需要用戶指定一個(gè)簽名、主頁URL、以及IM address等. 使用Membership model,有2種方法來將用戶帳戶與額外的信息聯(lián)系起來.第一種,具有最大的靈活性也要做最多的準(zhǔn)備工作——為額外信息創(chuàng)建自定義數(shù)據(jù)存儲(chǔ).如果你使用的是SqlMembershipProvider,那就意味著要?jiǎng)?chuàng)建一個(gè)額外的表,將aspnet_Users表的UserId值作為主鍵.以一個(gè)在線messageboard為例,該表可為forums_UserProfile,具有的列為UserId(將aspnet_Users表的UserId作為主鍵和外鍵)、HomepageUrl、 Signature、 IMAddress. 另外,我們還可以使用ASP.NET 2.0 Profile system來存儲(chǔ)用戶的具體信息.Profile system允許定義與用戶相關(guān)的屬性。一旦定義后,開發(fā)者就可以通過編程來讀取和訪問這些屬性的值.與Membership、Roles類似,Profile system也是基于provider model,默認(rèn)情況下,.NET Framework有一個(gè)SqlProfileProvider class類,它使用一個(gè)SQL Server數(shù)據(jù)庫表(aspnet_Profile)來作為其存儲(chǔ)備份(backing store). 在本文,我們將考察Profile system——如何定義用戶屬性以及如何從ASP.NET頁面來編程訪問它們。同時(shí)我們還將看到.NET 2.0里的SqlProfileProvide使用自定義的profile provider。 概述Profile System ASP.NET 2.0里面的Membership system設(shè)計(jì)來創(chuàng)建處理用戶帳戶的標(biāo)準(zhǔn)API.雖然Membership system有與用戶相關(guān)的核心屬性—username, password, email address等,但是我們還經(jīng)常需要獲取每個(gè)用戶的其它信息.而且每個(gè)程序之間的額外信息還彼此不同. 為此,微軟創(chuàng)建Profile system來處理這些額外的用戶屬性.Profile system允許將這些用戶屬性定義在Web.config文件并將其值存儲(chǔ)在某些數(shù)據(jù)存儲(chǔ)里.默認(rèn)的Profile provider - SqlProfileProvider,將這些屬性值存儲(chǔ)在一個(gè)叫aspnet_Profile的SQL Server數(shù)據(jù)庫表里. 當(dāng)使用Profile system時(shí),我們要記住其唯一的目的是作為一種定義一系列用戶屬性的方法.再通過某個(gè)具體的provider,將這些屬性值存儲(chǔ)在某些backing store里. 定義用戶屬性 用Profile system,我們必須要在Web.config文件里定義清楚.對(duì)每個(gè)屬性我們要指定其name, 數(shù)據(jù)類型,以及數(shù)據(jù)應(yīng)如何序列化(serialized).如下為4個(gè)serialization選項(xiàng): .ProviderSpecific(默認(rèn))—Profile provider要決定如何序列化屬性值. .String—屬性值將轉(zhuǎn)換成一個(gè)字符串形式 .Xml—屬性值將轉(zhuǎn)換成一個(gè)XML形式 .Binary—屬性值將轉(zhuǎn)換成一個(gè)二進(jìn)制形式 你選擇哪種serialization方法取決于變量的類型.如果允許將屬性值轉(zhuǎn)化為一個(gè)String,那么我們就要讓provider將數(shù)據(jù)序列化為一個(gè)String;對(duì)XML和Binary類型,以此類推. 定義在Profile system的屬性可為簡(jiǎn)單的標(biāo)量類型(scalar),進(jìn)而在聚合(grouped into)成復(fù)雜的類型,或已存在的復(fù)雜類型(例如一個(gè)類)。每個(gè)Profile屬性的names, types,和serialization都定義在<profile> 元素的<properties>節(jié)點(diǎn).比如,假象我們要用戶指定一個(gè)主頁的URL,我們可以添加如下的屬性: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> ... <profile defaultProvider="CustomProfileProvider" enabled="true"> <providers> ... </providers> <!-- Define the properties for Profile... --> <properties> <add name="HomepageUrl" type="String" serializeAs="String" /> ... </properties> </profile> </system.web> </configuration> <add>元素添加了一個(gè)名為HomepageUrl,類型為String,serialized為String的屬性。除此之外我們還可以在<add>元素添加額外的屬性. 標(biāo)量類型的屬性可以通過使用<group>元素進(jìn)行聚合。比如,除了HomepageUrl屬性外,我們還想獲取用戶的實(shí)際位置、生日、選用的編程語言等.這些信息可以分別為3個(gè)標(biāo)量值,也可以進(jìn)行聚合.如下的代碼顯示如何將這3個(gè)屬性值聚合為一個(gè)名為Bio的組. <profile defaultProvider="CustomProfileProvider" enabled="true"> <providers> ... </providers> <!-- Define the properties for Profile... --> <properties> <add name="HomepageUrl" type="String" serializeAs="String" /> <group name="Bio"> <add name="BirthDate" type="DateTime" serializeAs="Xml" /> <add name="Location" type="String" /> <add name="ProgrammingLanguageOfChoice" type="ProgrammingLanguages" /> </group> ... </properties> </profile> 上述代碼里,BirthDate屬性(類型為DateTime)被選作序列化為XML,而Location 和 ProgrammingLanguageOfChoice屬性未指定serializeAs屬性,那意味著Profile provider將自行決定如何序列化這2個(gè)屬性.注意ProgrammingLanguageOfChoice屬性的類型,該類型是我們?cè)贏pp_Code文件夾里創(chuàng)建的。代碼如下: Public Enum ProgrammingLanguages As Integer NoneSelected = 0 VB = 1 CSharp = 2 JSharp = 3 End Enum 此外,Profile屬性的類型還可以為一個(gè)自定義類,在本文下載內(nèi)容里,你將發(fā)現(xiàn)一個(gè)很簡(jiǎn)單的Address class類(也是在App_Code文件夾): <Serializable()> _ Public Class Address Public Address1 As String Public Address2 As String Public City As String Public State As String Public Zip As Integer End Class 定義了上述類后,我們可以添加一個(gè)Address類型的屬性,如下: <profile defaultProvider="CustomProfileProvider" enabled="true"> <providers> ... </providers> <!-- Define the properties for Profile... --> <properties> <add name="HomepageUrl" type="String" serializeAs="String" /> <group name="Bio"> <add name="BirthDate" type="DateTime" serializeAs="Xml" /> <add name="Location" type="String" /> <add name="ProgrammingLanguageOfChoice" type="ProgrammingLanguages" /> </group> <add name="BillingAddress" type="Address" serializeAs="Xml" /> <add name="ShippingAddress" type="Address" serializeAs="String" /> </properties> </profile> 上述代碼里,BillingAddress 和 ShippingAddress屬性都為Address類型. 在代碼里處理Profile屬性 完成Profile屬性的定義后,ASP.NET引擎自動(dòng)地創(chuàng)建一個(gè)ProfileCommon class類,該類包含的屬性與我們?cè)赪eb.config文件里定義的屬性相匹配.當(dāng)我們?cè)赪eb.config文件里修改這些屬性后,該類將重新創(chuàng)建并自動(dòng)處理當(dāng)前登錄用戶的profile.(你也可以設(shè)置profile對(duì)匿名用戶的支持,不過這不是本文的主題,我們將在后面的文章探討). 可以在一個(gè)ASP.NET頁面里通過HttpContext對(duì)象的Profile屬性來訪問ProfileCommon class類。比如,要在一個(gè)ASP.NET頁面里讀取當(dāng)前登錄用戶的HomepageUrl屬性,僅僅只需要使用Profile.HomepageUrl即可. 實(shí)際上,只要你輸入Profile再鍵入一個(gè)“.”智能感知功能將帶出各種屬性??釂??實(shí)際上聚合功能同樣工作地很好,輸入Profile再鍵入一個(gè)“.”,你將看到其中一個(gè)屬性為Bio.輸入Bio再鍵入一個(gè)“.”,那3個(gè)標(biāo)量屬性就出現(xiàn)在智能感知界面里(BirthDate, Location, and ProgrammingLanguageOfChoice). 本文下載代碼里有3個(gè)頁面值得考察,第一個(gè)頁面為/UsersOnly/Default.aspx頁面,顯示了當(dāng)前登錄用戶的Profile信息.第二個(gè)頁面為/UsersOnly/UpdateProfile.aspx,允許用戶更改其Profile數(shù)據(jù).第三個(gè)頁面演示了如何使用Profile屬性的GetProfile("username")方法來獲取其它,非當(dāng)前登錄用戶的Profile數(shù)據(jù).頁面/UserList.aspx列出了系統(tǒng)里的所有用戶的membership信息(username, email等),以及HomepageUrl屬性值. 指定一個(gè)Profile Provider 如果你沒有顯式地指定一個(gè)Profile provider,那么默認(rèn)使用的是SqlProfileProvider,它將用戶的property值存儲(chǔ)在aspnet_Profile表里,但效率比較低,該表的構(gòu)架如下: 對(duì)于給定的記錄,PropertyNames列包含的是每個(gè)Profile屬性的名稱,根據(jù)其序列化形式的不同,將其值存儲(chǔ)在PropertyValuesString 或 PropertyValuesBinary列.如果是以String或 XML形式則存儲(chǔ)在PropertyValuesString列;如果是以Binary形式則在PropertyValuesBinary列. 就我們定義的Profile屬性而言,該某個(gè)用戶的PropertyNames列的值可能為: Bio.ProgrammingLanguageOfChoice:S:0:92:HomepageUrl:S:92:30:ShippingAddress:B:0:212:... 如你所見,每個(gè)property name的形式為PropertyName:B|S:StartIndex:Length,其中B 或 S指出了該屬性的值是存儲(chǔ)在PropertyValuesString(S)列 還是在 PropertyValuesBinary(B)列的.比如,Bio.ProgrammingLanguageOfChoice屬性的值存儲(chǔ)在PropertyValuesString (S)列,起始位置為0,長(zhǎng)度為92.而HomepageUrl屬性的值也存儲(chǔ)在PropertyValuesString (S)列,起始位置為92,長(zhǎng)度為30. 查看PropertyValuesString列,我們看到: <?xml version="1.0" encoding="utf-16"?><ProgrammingLanguages>CSharp</ProgrammingLanguages>http://www.... ProgrammingLanguageOfChoice的值已經(jīng)被序列化為XML形式,開始位置為0,長(zhǎng)度為92;同樣,HomepageUrl屬性開始位置為92,長(zhǎng)度為30.(而ShippingAddress屬性為Binary形式,我們可以在PropertyValuesBinary列里找到其值,開始位置為0.長(zhǎng)度為212) SqlProfileProvider自動(dòng)的將Profile屬性遷移到數(shù)據(jù)庫.而SqlProfileProvider用到的表和存儲(chǔ)過程是在貫徹SqlMembershipProvider時(shí)自動(dòng)創(chuàng)建的(見Part 1). SqlProfileProvider的局限性 由于SqlProfileProvider將所有的屬性值壓縮到一行的1到2列,每次對(duì)任何一個(gè)屬性值的讀取都要觸動(dòng)所有的屬性值;另外數(shù)據(jù)的格式也使的我們很難查詢和返回這些屬性信息。假如我們想知道有多少用戶使用C#(該信息存儲(chǔ)在PropertyValuesString列),我們首先需要將其數(shù)據(jù)格式轉(zhuǎn)換成正常的數(shù)據(jù)結(jié)構(gòu). 作為SqlProfileProvider的替代,我們可以使用微軟雇員Hao Kung開發(fā)的免費(fèi)的Table Profile Provider(http://www./downloads/sandbox/table-profile-provider-samples/)。該provider將每個(gè)Profile屬性存儲(chǔ)在各自的列里。另外,我們開可以創(chuàng)建自己的Profile provider. 結(jié)語: 除了username, password, email address這些基本的用戶信息外,如果你還想獲取更多的用戶信息,你要么使用自定義的解決方案(創(chuàng)建你自己的數(shù)據(jù)存儲(chǔ),寫代碼來對(duì)數(shù)據(jù)存儲(chǔ)進(jìn)行數(shù)據(jù)讀寫),要么使用Profile system. 它允許頁面開發(fā)者在Web.config文件里定義一系列的用戶屬性,這些信息自動(dòng)的轉(zhuǎn)換為一個(gè)類(ProfileCommon),并可以通過HttpContext class類的Profile屬性來進(jìn)行訪問. ASP.NET 2.0默認(rèn)的Profile provider為SqlProfileProvider,它將Profile屬性值存儲(chǔ)在一個(gè)SQL Server數(shù)據(jù)庫的aspnet_Profile表里.我們只需要通過Profile屬性來讀寫用戶的Profile數(shù)據(jù). 祝編程快樂! 考察ASP.NET 2.0的Membership, Roles, and Profile - Part 7 導(dǎo)言: 在前6章我們考察了.NET Framework包括的那些provider——比如SqlMembershipProvider, SqlRoleProvider, SqlProfileProvider等.實(shí)際上 我們可以下載這些provider的源代碼,以及一個(gè)Provider工具包來創(chuàng)建我們自己的provider(http://msdn2.microsoft.com/en- us//aa336558.aspx),而Scott Guthrie在他的博客文章《ASP.NET 2.0 Membership, Roles, Forms Authentication, and Security Resources》(http://weblogs./scottgu/archive/2006/02/24/ASP.NET-2.0-Membership_2C00_-Roles_2C00_-Forms- Authentication_2C00_-and-Security-Resources-.aspx)里列出了很多自定義的Membership, Roles, and Profile provider. 如果這些內(nèi)置的provider無法滿足你的需要,你可以創(chuàng)建自己的provider.本文,我們將探討創(chuàng)建和使用一個(gè)自定義provider,然后用一個(gè)簡(jiǎn)單 的自定義provider將profile信息存儲(chǔ)到一個(gè)XML文件里. Profile System的職責(zé) 像在Part 6探討的一樣,Profile System允許用戶在Web.config文件定義一系列的 "profile properties",然后在某些存儲(chǔ)備份(backing store)里保存和讀取這些屬性值. 如果這些內(nèi)置Profile providers不能滿足需要,你可以創(chuàng)建你自己的provider。創(chuàng)建一個(gè)用戶定制provider——不管是用于Profile, Membership, Roles, ASP.NET site map,或是其他的什么子系統(tǒng),都有遵循如下的步驟: 1.創(chuàng)建用戶定制provider——?jiǎng)?chuàng)建源自ProfileProvider class類的一個(gè)類. 2.設(shè)置應(yīng)用程序使用用戶定制provide——我們需要在Web.config文件里指定Profile system使用我們的定制provid而不是默認(rèn)的 SqlProfileProvider。 微軟的Provider Toolkit web page頁面里有關(guān)于學(xué)習(xí)創(chuàng)建用戶定制provider的信息.對(duì)Profile system而言,有2個(gè)文件值得閱讀: 《Introduction to Profile Providers》——它介紹了Profile system的概念以及職責(zé);而《ASP.NET 2.0's Profile Providers》——它更 直觀的介紹了 in ASP.NET 2.0里的SqlProfileProvider是如何貫徹的. 本文的剩下部分我們將探討我們自定義的XmlProfileProvider——將用戶信息裝入App_Data文件夾里的一個(gè)XML文件,完整代碼(以及簡(jiǎn)單的測(cè) 試程序)在本文的下載代碼里. 設(shè)計(jì)XmlProfileProvider 默認(rèn),Membership, Roles,Profile system的provider都被設(shè)計(jì)為多個(gè)應(yīng)用程序存儲(chǔ)信息.明顯的例子就是aspnet_Applications表,每一個(gè)應(yīng)用程序?qū)嵗龑?duì)應(yīng)一條記錄.系統(tǒng)里的每一個(gè)用戶通過aspnet_Users表里的ApplicationId這個(gè)外鍵與某個(gè)應(yīng)用程序聯(lián)系起來.我決定將該功能應(yīng)用到我們的profile provider里(對(duì)XmlProfileProvider來說,Membership 和 Roles providers都可以使用它).Profile數(shù)據(jù)默認(rèn)時(shí)存儲(chǔ)在App_Data文件夾里的一個(gè)文件里,以阻止用戶從瀏覽器直接請(qǐng)求這些文件(如果一個(gè)用戶試圖從瀏覽器訪問http://www./App_Data/anyFile 的話,ASP.NET會(huì)返回一個(gè)HTTP 404消息)。不過你也可以通過 provider的profileFolder設(shè)置來指定XML文件存放在什么地方. 具體來說,Profile數(shù)據(jù)以如下形式進(jìn)行存儲(chǔ):~/App_Data/XmlProfiles/applicationName/username.xml.每一個(gè)XML文件開始為一個(gè)<profileData>根元素,而子元素就由定義在Web.config文件里的Profile屬性里決定了。 就像在Part 6探討了一樣,Profile屬性可以為strings, XML,或binary數(shù)據(jù),對(duì)string類型的屬性而言,XML文件將其保存為文本形式;如果是XML類型則原封不動(dòng)的保存;如果是binary類型的就保存為64位編碼的binary.假設(shè)我們?cè)赪eb.config文件<properties>元素里定義了6個(gè)Profile屬性: <profile defaultProvider="..."> <providers> ... </providers> <properties> <add name="Birthdate" type="DateTime" serializeAs="String" /> <add name="HomepageUrl" type="String"/> <add name="Signature" /> <add name="IncludeSignatureInPosts" type="Boolean"/> <add name="BillingAddress" type="Address" serializeAs="Xml" /> <add name="ShippingAddress" type="Address" serializeAs="Binary" /> </properties> </profile> 其中的Address類型是定義在App_Code文件夾里的一個(gè)簡(jiǎn)單類,包含了些標(biāo)量屬性,比如:Address1, Address2, City等.注意:Profile屬性BillingAddress序列化為XML,而ShippingAddress為binary. 對(duì)于上面定義的Profile屬性,如果有個(gè)叫"Jisun"的用戶登錄我們的網(wǎng)站,使用Profile system,且應(yīng)用程序的名稱為"MyApp",那么將會(huì)創(chuàng)建一個(gè)~/App_Data/XmlProfiles/MyApp/Jisun.xml的文件,其包含的代碼可能為: <?xml version="1.0" encoding="utf-8"?> <profileData> <IncludeSignatureInPosts>False</IncludeSignatureInPosts> <Signature>What is life, but a seemingly random collection of 1s and 0s?</Signature> <HomepageUrl>http://www.</HomepageUrl> <Birthdate>1979-04-01</Birthdate> <ShippingAddress><![CDATA[AAEAAAD/////AQAAAAAAAAAMAHBfQ29kZS5j...]]></ShippingAddress> <BillingAddress> <Address xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:xsd="http://www./2001/XMLSchema"> <Address1>123 Anywhere St.</Address1> <Address2 /> <City>San Diego</City> <State>CA</State> <ZipCode>92109</ZipCode> </Address> </BillingAddress> </profileData> 就像你看見的那樣,每個(gè)Profile屬性被處理成一個(gè)XML元素并作為<profileData>根元素的子元素. 對(duì)string類型的屬性,比如IncludeSignatureInPosts, Signature, HomepageUrl,以及Birthdate,其值在XML元素里為文本值;對(duì)XML類型的屬性(BillingAddress),其值在<BillingAddress>元素里保存為原始形式;binary類型的屬性ShippingAddress被編碼為64位. 規(guī)劃XmlProfileProvider Class類 當(dāng)構(gòu)建用戶定制Profile provider時(shí),我們要擴(kuò)充System.Web.Profile.ProfileProvider class類.至少要包含2個(gè)方法——GetPropertyValues(context, collection) 和 SetPropertyValues(context, collection).這2個(gè)方法都接受2個(gè)輸入?yún)?shù)——context 和 collection. 其中context提供的信息為:用戶名以及該用戶是否經(jīng)過認(rèn)證(ASP.NET支持匿名profile,不過這超出了本文的范圍,更多信息請(qǐng)參閱文章《Profiles section on the ASP.NET Quickstarts 》(http:///QuickStartv20/aspnet/doc/profile/default.aspx#anon));另外collection提供一系列的Profile屬性. 上面的GetPropertyValues方法返回所需Profile屬性的值,相反SetPropertyValues方法的目的是向backing store(就本例而言,為XML文件)寫入屬性值.在ProfileProvider class類里還有其它的類,不過我們可以創(chuàng)建僅僅執(zhí)行這2個(gè)方法的自定義profile provider. 在你的Website里使用XmlProfileProvider自定義Provider 為了在你的應(yīng)用程序里使用自定義的XmlProfileProvider,我們首先要在本文結(jié)尾處下載其代碼,將CustomProviders.dll放在你的web 應(yīng)用程序的/bin目錄,再更新你的Web.config文件: <profile defaultProvider="MyCustomProfileProvider"> <providers> <clear /> <add name="MyCustomProfileProvider" type="CustomProviders.XmlProfileProvider, CustomProviders" applicationName="applicationName" [profileFolder="baseFolderPathForProfileXMLFiles"] /> </providers> <properties> ... </properties> </profile> 其中profileFolder屬性是可選的,如果忽略的話,默認(rèn)為~/App_Data/XmlProfiles/. 下載代碼里包含了一個(gè)測(cè)試的web應(yīng)用程序,指導(dǎo)如何將自定義的XmlProfileProvider class類與默認(rèn)的SqlMembershipProvider class類協(xié)調(diào)使用. 結(jié)語: 在本文我們看到如何利用provider model來創(chuàng)建以用戶自定義的Profile provider,它將用戶屬性設(shè)置保存為XML文件而不是一個(gè)數(shù)據(jù)庫. 祝編程快樂! 考察ASP.NET 2.0的Membership, Roles,Profile - Part 8 導(dǎo)言: 我最近遇到一個(gè)網(wǎng)站,其主要包含一些靜態(tài)的內(nèi)容.在客戶端,需要一個(gè)頁面來從一個(gè)數(shù)據(jù)庫表里顯示數(shù)據(jù).另外,還需要一個(gè)頁面來便于管理員添加、更新、刪除數(shù)據(jù).用ASP.NET 2.0的數(shù)據(jù)源控件以及Membership system,該功能可以很容易的實(shí)現(xiàn)。不過有一個(gè)問題,由于服務(wù)器不支持SQL Server數(shù)據(jù)庫,只有用Access數(shù)據(jù)庫來代替。問題來了,.NET Framework BCL只包含了一個(gè)支持Microsoft SQL Server數(shù)據(jù)庫的Membership provider. 可喜的是,微軟提供了一個(gè)Access數(shù)據(jù)庫模板及在Membership, Roles,Profile里使用Access數(shù)據(jù)庫的provider.在本文我們將探討如何得到這些基于Access的provider以及如何在ASP.NET 2.0 web應(yīng)用里使用它們.獲取并使用Access Provider 在ASP.NET 2.0的Beta版本里,微軟為Membership, Roles, Profile設(shè)計(jì)的基于Access和SQL Server數(shù)據(jù)庫的provider,并作為基本類庫的一部分包含在.NET Framework里.到ASP.NET 2.0 正式發(fā)行的時(shí)候,微軟決定剔除內(nèi)置的對(duì)Access數(shù)據(jù)庫的支持,而只支持Microsoft SQL Server 2005 Express Edition版本數(shù)據(jù)庫.但是不見得所有人都轉(zhuǎn)移到SQL Server 2005.很多web服務(wù)器公司就不支持Express Edition.其它人可能在此之前設(shè)計(jì)的是基于Access數(shù)據(jù)庫的應(yīng)用程序并使用的很好,要轉(zhuǎn)變到SQL Server的話可能困難重重. 還好,我們可以從微軟單獨(dú)下載到Access providers,其為一個(gè)Microsoft Visual Studio安裝文件(VSI),包含了C# class類文件以及一個(gè)Access數(shù)據(jù)庫.你可以在這里:http://download.microsoft.com/download/5/5/b/55bc291f-4316-4fd7-9269-dbf9edbaada8/SampleAccessProviders.vsi進(jìn)行下載,當(dāng)然在本文的下載文件里也包含它. 我們必須采取以下3個(gè)步驟才能使用Access providers: 1.將Access Provider Classes類應(yīng)用到Web Application——下載內(nèi)容里的C# class類文件要么被編譯為一個(gè)文件并放到web應(yīng)用程序的/bin目錄文件夾里,要么將這些類文件拷貝到App_Code文件夾. 2.準(zhǔn)備好數(shù)據(jù)庫——確保應(yīng)用程序里有一個(gè)Access數(shù)據(jù)庫. 3.更新Web.config文件—必須對(duì)Web.config文件進(jìn)行設(shè)置以使應(yīng)用程序?yàn)镸embership, Roles,Profile調(diào)用Access providers而不是默認(rèn)的SQL Server providers. 第一步:將Access Provider Classes類應(yīng)用到Web Application 下載完該VSI文件后,雙擊以進(jìn)行安裝過程,這將把文件安裝到恰當(dāng)?shù)奈募A(就我的電腦而言:My Documents\Visual Studio 2005\Templates\ProjectTemplates\Visual Web Developer\Starter Kits).在“New Projects”對(duì)話框里可以找到一個(gè)模板,如下面的截屏所示: 創(chuàng)建一個(gè)新工程,用該ASP.NET Access Providers模板創(chuàng)建一個(gè)Class Library對(duì)象.在此,最理想的是將Class Library對(duì)象進(jìn)行編譯得到一個(gè)文件,比如AccessProviders.dll.再將其拷貝到應(yīng)用程序的/bin目錄下,這將允許你為Membership, Roles, Profile調(diào)用Access provider. 這是最理想的方法因此它便于部署和維護(hù). 另外,你還可以將模板使用的C# class類文件拷貝到應(yīng)用程序的App_Code文件夾里.最簡(jiǎn)單的方法是從下載的VSI文件里將其抽出來,在安裝向?qū)У牡谝徊嚼铮x擇"View files in Windows Explorer",該VSI文件包含一個(gè)ZIP壓縮文件(ASP.NET Access Providers.zip),在它的Samples目錄下包含了必需的類.將這些類拷貝進(jìn)App_Code文件夾. 第二步:準(zhǔn)備好數(shù)據(jù)庫 該VSI文件包含了一個(gè)Microsoft Access數(shù)據(jù)庫(ASPNetDB.mdb),其包含了必需的表和視圖.我們要將該數(shù)據(jù)庫放在我們的應(yīng)用程序里。我們可以在Windows資源管理器里查找到VSI里包含的Access數(shù)據(jù)庫;或者安裝完VSI后,我們也可以在硬盤里找到該數(shù)據(jù)庫.不管是哪種方式,你都要將這個(gè)ASPNetDB.mdb數(shù)據(jù)庫拷貝到App_Data文件夾.確保該文件沒有標(biāo)明為只讀,這樣那些用戶帳戶才有對(duì)App_Data文件夾的讀寫權(quán)限. 第三步:更新Web.config文件 最后我們要更新Web.config文件,以使Membership, Roles,Profile使用基于Access的provider而不是默認(rèn)的基于SQL Server的provider.我們也需要在<connectionStrings>節(jié)點(diǎn)引用該Access數(shù)據(jù)庫的路徑. 首先添加新的<connectionStrings>,假定你的數(shù)據(jù)庫還是ASPNetDB.mdb且放在App_Data文件夾里,你可以使用如下的代碼: 程序代碼
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<connectionStrings> <add name="LocalAccessDatabase" connectionString="~/App_Data/ASPNetDB.mdb" providerName="System.Data.OleDb"/> </connectionStrings> <system.web> ... </system.web> </configuration> 接下來在<system.web>元素,添加必要的Membership, Roles,Profile元素.下面的聲明清除了默認(rèn)的Membership provider設(shè)置,而將AccessMembershipProvider作為應(yīng)用程序默認(rèn)的Membership provider: 程序代碼
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<connectionStrings> <add name="LocalAccessDatabase" connectionString="~/App_Data/ASPNetDB.mdb" providerName="System.Data.OleDb"/> </connectionStrings> <system.web> <membership defaultProvider="AccessMembershipProvider"> <providers> <clear/> <add name="AccessMembershipProvider" type="Samples.AccessProviders.AccessMembershipProvider, AssemblyName" connectionStringName="LocalAccessDatabase" enablePasswordRetrieval="false" enablePasswordReset="false" requiresUniqueEmail="false" requiresQuestionAndAnswer="false" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" applicationName="SampleSite" hashAlgorithmType="SHA1" passwordFormat="Hashed"/> </providers> </membership> </system.web> </configuration>
|
|