一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

考察ASP.NET 2.0Membership,Roles,Profile

 laixuexideren 2010-08-13
考察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>



我們注意到<connectionStrings>節(jié)點(diǎn)用到的name與<add>元素里的connectionStringName屬性的值一樣(都是LocalAccessDatabase).如果你將類編譯成一個(gè)文件并拷貝到/bin目錄的話,type應(yīng)該使用"Samples.AccessProviders.AccessMembershipProvider, AssemblyName";而如果你將類文件拷貝到App_Code文件夾的話,type應(yīng)該使用 "Samples.AccessProviders.AccessMembershipProvider".

一旦完成上面3個(gè)步驟后,你就按同一種方式來使用Membership, Roles, Profile system就像是在使用默認(rèn)的基于SQL Server的provider一樣(也不完全正確,見如下的警告以及VSI里的README文件)。這意味著你可以使用Security Web控件——Login, LoginView, CreateUserWizard等.本文下載代碼里包含了一個(gè)簡(jiǎn)單的website,它的Membership 和 Roles功能調(diào)用的是Access providers.

關(guān)于使用Access-based Providers的警告

VSI里的README文件指出了使用Access Membership provider的缺點(diǎn),我這里再次重申:

1——在CreateUser 和 ChangePassword方法里并沒有強(qiáng)制性的對(duì)密碼長(zhǎng)     度做出要求,該設(shè)置可以進(jìn)行讀取但不能被provider使用.

2——不能在provider里執(zhí)行帳戶鎖定,自然,UnlockUser方法也無效.同      時(shí)不能阻止帶有惡意的password 或password answer的企圖.

3——不支持創(chuàng)建帶有一個(gè)明顯UserId(比如providerUserKey)的新用戶

4——不支持創(chuàng)建檢索一個(gè)基于UserId(比如providerUserKey)的用戶

參見README文件以獲取更多的信息


結(jié)語:

本文我們考察了適用于Membership, Roles,Profile的Access providers,它允許開發(fā)者使用一個(gè)Access數(shù)據(jù)庫來作為Membership, Roles, 以及 Profile systems的存儲(chǔ)備份(backing store)

祝編程快樂!

下載示例程序

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    一区二区日本一区二区欧美| 91人妻人人做人碰人人九色| 成人精品一区二区三区在线| 成人精品日韩专区在线观看| 九九久久精品久久久精品| 国产丝袜女优一区二区三区| 国产又粗又硬又大又爽的视频| 精品国自产拍天天青青草原| 午夜精品一区二区三区国产| 日韩成人中文字幕在线一区| 最新午夜福利视频偷拍| 少妇被粗大进猛进出处故事| 麻豆在线观看一区二区| 字幕日本欧美一区二区| 日本高清加勒比免费在线| 在线观看中文字幕91| 青青操精品视频在线观看| 欧美黑人暴力猛交精品| 五月婷婷综合缴情六月| 欧美精品亚洲精品日韩专区| 欧美精品专区一区二区| 亚洲男人天堂网在线视频| 国产日韩精品激情在线观看| 国产传媒一区二区三区| 精品少妇人妻一区二区三区| 人妻内射在线二区一区| 国产三级黄片在线免费看 | 久久精品国产在热久久| 我要看日本黄色小视频| 国内九一激情白浆发布| 亚洲中文在线观看小视频| 国产日韩熟女中文字幕| 国产精品欧美一区两区| 日韩欧美亚洲综合在线| 九九热视频经典在线观看| 国产一区一一一区麻豆| 丝袜视频日本成人午夜视频| 男人大臿蕉香蕉大视频| 色老汉在线视频免费亚欧| 五月的丁香婷婷综合网| 午夜精品一区二区三区国产|