在 SQL Server 中创建Membership Schema

本文档是Visual C# 教程 (转至 Visual Basic 教程

本教程首先探讨在数据库中增加必要的架构(schema) 以使用SqlMembershipProvider 的技术。然后,我们再探讨架构中的关键表,并讨论它们的目的和重要性。最后,我们探讨如何告诉ASP.NET 应用程序Membership 框架应该使用哪个提供者。

<<前一篇教程下一篇教程>>

简介

前两篇教程探讨了使用表单身份验证来识别网站访问者。表单身份验证框架让开发人员可以很容易地使用户登录网站,并在页面间切换时通过使用身份验证票证记住他们。FormsAuthentication类包含了生成票证并将票证添加到访问者的cookies 中的方法。FormsAuthenticationModule则对所有的进入请求进行检查,对那些具有有效身份验证票证的请求,创建GenericPrincipalFormsIdentity对象并与当前请求关联起来。表单身份验证只是一种机制,对登录的用户创建一个身份验证票证,对于后续的请求,通过解析该票证来确定用户的身份。对于支持用户帐户的web 应用程序,我们仍然需要实现用户存储同时添加功能以验证凭证、注册新用户,以及各种与用户帐户相关的其它任务。

在ASP.NET 2.0 以前,开发人员要自己处理所有与用户帐户相关的任务。幸运的是,ASP.NET 团队意识到了该缺点并在ASP.NET 2.0 中引入了Membership 框架。Membership 框架是.NET Framework 中的一系列类,它提供了处理与用户帐户有关的核心任务的编程接口。该框架基于提供者模式之上,它允许开发人员将定制实现插入到标准的API 中。

正如《安全基础和 ASP.NET 支持》教程中所探讨的,.NET Framework 有两个内置的Membership 提供者:ActiveDirectoryMembershipProviderSqlMembershipProvider。顾名思义,SqlMembershipProvider 使用 Microsoft SQL Server 数据库作为用户存储。为在应用程序中使用该提供者,我们需要告诉提供者使用哪个数据库作为存储。可能您已经想到了,SqlMembershipProvider 期望用户存储数据库中有某些数据库表、视图和存储过程。我们需要在选定的数据库中添加这些预期的架构。

本教程首先探讨在数据库中添加必要的架构以使用SqlMembershipProvider 的技术。然后,我们再探讨架构中的关键表,并讨论它们的目的和重要性。最后,我们探讨如何告诉ASP.NET 应用程序Membership 框架应该使用哪个提供者。

让我们开始吧 !

步骤1:决定将用户存储放在哪儿

ASP.NET 应用程序的数据通常存储在数据库中的多个表中。实现SqlMembershipProvider 数据库架构时,我们必须决定是将Membership 架构与应用程序数据一起存储在同一数据库中,还是另外一个数据库中。

我建议将Membership 架构与应用程序数据一起存储在同一数据库中,原因如下:

  • 可维护性 � 其数据被封装在一个数据库中的应用程序比具有两个独立数据库的应用程序更容易理解、维护和部署。
  • 关系完整性 � 通过将与 Membership 有关的表和应用程序表放在同一个数据库中,与Membership 有关的表的主键和相关应用程序表的主键之间建立外键约束成为可能。

将用户存储和应用程序数据分开存储在不同的数据库中,只有在这种情况下才有意义:您有多个应用程序,每个应用程序都使用单独的数据库,但需要共享用户存储。

创建数据库

在第二篇教程中创建的应用程序还没有用到数据库。但现在需要一个数据库来存放用户存储。让我们创建一个数据库,并将其添加到SqlMembershipProvider 提供者所需的架构(参见步骤2)。

注意: 在本教程系列中,我们将使用 Microsoft SQL Server 2005 Express Edition 数据库来存储我们的应用程序表和SqlMembershipProvider 架构。该决定基于两个原因:首先,它是免费的,Express Edition 是 SQL Server 2005 的最容易理解的版本;再者,SQL Server 2005 Express Edition 数据库可以直接放在Web 应用程序的App_Data 文件夹中,这样我们就可以将数据库与web 应用程序一起打包成一个ZIP 文件,在重新部署时不需要特殊的安装指示或配置选项。如果您更喜欢使用SQL Server的非 Express 版本,随意吧。步骤其实都是一样的。SqlMembershipProvider 架构与Microsoft SQL Server 2000 的各种版本以及更高版本都能兼容。

在 Solution Explorer 中右键单击 App_Data 文件夹,选择 Add New Item 。(如果您在项目中没有看到 App_Data 文件夹,在 Solution Explorer 中右键单击项目,选择 Add ASP.NET Folder ,再选择 App_Data 。 )在 Add New Item 对话框中,选择添加一个名为 SecurityTutorials.mdf 的新 SQL 数据库。在本教程中,我们将 SqlMembershipProvider 架构添加到该数据库中,在以后的教程中,我们再创建其它的表来存储我们的应用程序数据。

图1:在App_Data 文件夹中添加一个名为SecurityTutorials.mdf 的新 SQL 数据库(单击此处查看实际大小的图像

App_Data文件夹中添加数据库后,将自动地将该数据库包含在Database Explorer 视图中。(在Visual Studio 的非 Express Edition 版本中,Database Explorer 也叫 Server Explorer。)进入Database Explorer,展开刚添加的SecurityTutorials数据库。如果您在屏幕上没有看到Database Explorer,进入View 菜单,选择Database Explorer,或按下Ctrl+Alt+S。如图2 所示,该SecurityTutorials数据库是空的,没有表、视图和存储过程。

图2:SecurityTutorials数据库目前为空(单击此处查看实际大小的图像

步骤2:在数据库中添加SqlMembershipProvider 架构

SqlMembershipProvider 需要在用户存储数据库中安装一系列特定的表、视图和存储过程。可通过aspnet_regsql.exe 工具添加这些必需的数据库对象。该文件位于%WINDIR%\Microsoft.Net\Framework\v2.0.50727\文件夹。

注意:aspnet_regsql.exe 工具提供命令行功能和图形用户界面。图形用户界面更友好,也是我们在本教程中要探讨的。命令行接口在需要自动添加SqlMembershipProvider 架构时有用,比如创建脚本或自动测试。

aspnet_regsql.exe 工具用于在指定的SQL Server 数据库中添加或移除ASP.NET 应用程序服务 。ASP.NET应用程序服务包含SqlMembershipProviderSqlRoleProvider 的架构,以及其它ASP.NET 2.0 框架的基于SQL 的提供者的架构。我们需要给aspnet_regsql.exe 工具提供两点信息:

  • 我们是要添加还是删除应用程序服务,以及
  • 要从哪个数据库添加或删除应用程序服务架构

在提示要使用的数据库时,aspnet_regsql.exe工具要求我们提供数据库所在的服务器名称、连接到数据库的安全凭证以及数据库名称。如果您使用的是SQL Server 的非 Express Edition 版,您应该会知道这些信息,因为这与您通过ASP.NET web 页面访问数据库时所必须提供的连接字符串信息是一样的。然而,在App_Data文件夹中使用SQL Server 2005 Express Edition数据库时,确定服务器和数据库名称却有点棘手。

我们在下一节探讨用来指定App_Data文件夹中的SQL Server 2005 Express Edition数据库的服务器和数据库名称的简单方法。如果您使用的不是SQL Server 2005 Express Edition,那就跳到“安装应用程序服务”一节。

确定App_Data文件夹中SQL Server 2005 Express Edition数据库的服务器和数据库名称

为使用aspnet_regsql.exe工具,我们需要知道服务器和数据库名称。服务器名称为localhost\InstanceName。一般说来,InstanceNameSQLExpress。不过,如果您是手动安装的SQL Server 2005 Express Edition(即,安装Visual Studio 时没有自动安装它),则您有可能选择了不同的实例名。

确定数据库名称有点棘手。App_Data文件夹中的数据库一般都有一个数据库名称,它包含一个全局惟一标识符以及数据库文件路径。我们需要确定数据库名称,以通过aspnet_regsql.exe添加应用程序服务架构。

确定数据库名称的最简便方法是通过SQL Server Management Studio。SQL Server Management Studio 提供管理SQL Server 2005 数据库的图形界面,但Express Edition of SQL Server 2005中没有自带该功能。还好,您可以下载免费的SQL Server Management Studio Express Edition。

注意: 如果您的系统中还安装有 SQL Server 2005 的非 Express Edition 版本,则很可能已经安装了Management Studio 的完整版。您可以使用该完整版来确定数据库名称,和下面列出的Express Edition 的步骤一样。

首先关闭Visual Studio,确保Visual Studio 在数据库文件上施加的所有锁都已关闭。然后,打开SQL Server Management Studio,连接到SQL Server 2005 Express Edition的localhost\InstanceName数据库。就如前面提到的那样,实例名可能为SQLExpress。对于Authentication 选项,选择Windows Authentication。

图3:连接到SQL Server 2005 Express Edition实例(单击此处查看实际大小的图像

连接到SQL Server 2005 Express Edition实例后,Management Studio 显示 Databases、Security 设置以及Server Objects 等文件夹。如果您展开Databases 选项卡,您将看到SecurityTutorials.mdf 数据库并未注册到数据库实例中。我们首先需要附加该数据库。

右键单击Databases 文件夹,从上下文菜单中选择Attach。这将显示Attach Databases 对话框。在此,单击Add 按钮,浏览到SecurityTutorials.mdf 数据库,单击OK。图 4 显示的是选择SecurityTutorials.mdf 数据库后的Attach Databases 对话框。图5 显示的是成功附加数据库后Management Studio 的 Object Explorer。

图4:附加SecurityTutorials.mdf 数据库(单击此处查看实际大小的图像

图5:SecurityTutorials.mdf 数据库出现在Databases 文件夹中(单击此处查看实际大小的图像

如图 5 所示,SecurityTutorials.mdf 数据库的名称相当深奥。我们将它更改为更有意义(且容易输入)的名称。右键单击该数据库,在上下文菜单中选择Rename,将它重命名为SecurityTutorialsDatabase 。这样做并没有改变文件名,只改变了数据库在SQL Server 中标识自己的名称。

图6:将数据库重命名为SecurityTutorialsDatabase单击此处查看实际大小的图像

到此,我们知道了SecurityTutorials.mdf 数据库文件的服务器和数据库名称:分别为localhost\InstanceNameSecurityTutorialsDatabase 。现在,我们可以通过aspnet_regsql.exe工具安装应用程序服务。

安装应用程序服务

为启动aspnet_regsql.exe工具,进入开始菜单并选择Run。在文本框中输入%WINDIR%\Microsoft.Net\Framework\v2.0.50727\aspnet_regsql.exe ,并单击 OK。或者,您也可以在Windows Explorer 中定位到相应的文件夹,并双击aspnet_regsql.exe文件。这两种方法的结果一样。

不带任何命令行参数运行aspnet_regsql.exe工具,将打开ASP.NET SQL Server Setup Wizard图形用户界面。使用向导可容易地在指定数据库上添加或删除ASP.NET 应用程序服务。向导的第一屏,如图7 所示,描述该工具的用途。

图7:使用  ASP.NET SQL Server Setup Wizard 添加 Membership 架构(单击此处查看实际大小的图像

向导的第二步,询问我们是添加还是删除应用程序服务。由于我们想添加SqlMembershipProvider 所需的表、视图和存储过程,所以选择“Configure SQL Server for application services” 选项。稍后,如果您想从数据库中删除该架构,可重新运行该向导,然后选择“Remove application services information from an existing database” 选项。

图8:选择“Configure SQL Server for Application Services” 选项(单击此处查看实际大小的图像

第三步提示输入数据库信息:服务器名称、身份验证信息以及数据库名称。如果您一直按照本教程进行,在App_Data 中添加了SecurityTutorials.mdf 数据库,将它附加到localhost\InstanceName,并将它重命名为SecurityTutorialsDatabase ,则使用下面的值:

  • Server:localhost\InstanceName
  • Windows authentication
  • Database:SecurityTutorialsDatabase

图9:输入数据库信息(单击此处查看实际大小的图像

输入数据库信息后,单击Next。最后一步是对要采取的步骤进行汇总。单击Next 安装应用程序服务,然后单击Finish 完成向导。

注意: 如果您使用 Management Studio 来附加数据库并重命名数据库文件,重新打开Visual Studio 之前,一定要分离该数据库并关闭Management Studio。要分离SecurityTutorialsDatabase数据库,右键单击该数据库名称,在Tasks 菜单中,选择Detach。

完成向导后,返回Visual Studio,进入Database Explorer。展开Tables 文件夹。您应该看到一系列以aspnet_ 前缀开头的表。同样,在Views 和 Stored Procedures 文件夹中也会看到各种视图和存储过程。这些数据库对象构成了应用程序服务架构。我们将在步骤3 中探讨与成员关系和角色有关的数据库对象。

图10:各种表、视图和存储过程已添加到数据库(单击此处查看实际大小的图像

注意:aspnet_regsql.exe 工具的图形用户界面安装的是完整的应用程序服务架构。但在命令行中执行aspnet_regsql.exe时,您可以指定要安装(或删除)的特定应用程序服务组件。因此,如果您只想添加SqlMembershipProviderSqlRoleProvider提供者所需的表、视图和存储过程,就在命令行中运行aspnet_regsql.exe。或者,您可以手动运行aspnet_regsql.exe 使用的那些T-SQL 创建脚本的子集。这些脚本位于WINDIR%\Microsoft.Net\Framework\v2.0.50727\文件夹,名称为InstallCommon.sql 、InstallMembership.sql 、InstallRoles.sql 、InstallProfile.sql 、InstallSqlState.sql 等。

到此,我们已创建了SqlMembershipProvider 所需的数据库对象。然而,我们还需要通知Membership 框架应使用SqlMembershipProvider(而不是ActiveDirectoryMembershipProvider),且SqlMembershipProvider 应该使用SecurityTutorials数据库。我们将在步骤4 中探讨如何指定要使用的提供者以及如何定制所选提供者的设置。不过,我们先更深入地探讨一下刚创建的数据库对象。

步骤3:探讨架构的核心表

在ASP.NET 应用程序中使用Membership 和 Roles 框架时,具体的实现细节由提供者进行封装。在以后的教程中,我们将通过.NET Framework 的MembershipRoles 类来与这些框架接口。使用这些高层API 时,我们没有必要关注底层细节,比如SqlMembershipProviderSqlRoleProvider 执行了哪些查询或改动了哪些表等。

虽然,我们在不了解步骤2 中创建的数据库架构的情况下,依然可以安心地使用Membership 和 Roles 框架。然而,在创建表存储应用程序数据时,我们可能需要创建与用户或角色有关的实体。如果在应用程序数据表和步骤2 中创建的表之间建立外键约束的话,这有助于熟悉SqlMembershipProviderSqlRoleProvider架构。此外,在某些极少数情况下,我们可能需要直接(而不是通过MembershipRoles 类)在数据库级与用户和角色存储接口。

将用户存储分区到应用程序

 Membership 和Roles 框架的设计思想是这样的:多个不同的应用程序可共享一个用户和角色存储。使用Membership 或 Roles 框架的ASP.NET 应用程序必须指定要使用的应用程序分区。简而言之,多个web 应用程序可使用同一个用户存储和角色存储。图11 描述的是分区到三个应用程序的用户存储和角色存储:HRSite、CustomerSite 和 SalesSite。这三个web 应用程序每个都有自己独有的用户和角色,不过它们的用户帐户和角色信息都物理存储在相同的数据库表中。

图11:可跨多个应用程序对用户帐户进行分区(单击此处查看实际大小的图像

aspnet_Applications 表就是定义这些分区的。使用该数据库存储用户帐户信息的每个应用程序在该表中都有一条记录。aspnet_Applications表有四列:ApplicationIdApplicationNameLoweredApplicationNameDescriptionApplicationId的类型为uniqueidentifier,是表的主键;ApplicationName 提供各个应用程序的惟一的、用户友好的名称。

其它与Membership 和 Role 有关的表都链接回aspnet_Applications 表中的ApplicationId字段。例如,aspnet_Users表包含每个用户帐户的记录,有一个ApplicationId外键字段;同aspnet_Roles表。这些表中的ApplicationId字段指定用户帐户或角色所属的应用程序分区。

存储用户帐户信息

用户帐户信息被存储在两个表中:aspnet_Usersaspnet_Membershipaspnet_Users表包含保留基本用户帐户信息的字段。三个最相关的列为:

  • UserId
  • UserName
  • ApplicationId

UserId 是主键(类型为uniqueidentifier)。UserName的类型为nvarchar(256),它和密码一起组成用户的凭证。(用户的密码被存储在aspnet_Membership表中。)ApplicationId将用户帐户和aspnet_Applications 中的特定应用程序链接起来。在UserNameApplicationId列上有一个复合UNIQUE 约束。这确保在给定应用程序中,每个UserName 是惟一的,但允许不同的应用程序使用同一个UserName

aspnet_Membership 表包含其它用户帐户信息,比如用户的密码、电子邮箱、上次登录日期和时间,等等。aspnet_Usersaspnet_Membership表中的记录是一对一的。通过aspnet_MembershipUserId字段来确保该关系,它是表的主键。同aspnet_Users表一样,aspnet_Membership包含ApplicationId字段,它将该信息与特定应用程序分区连结起来。

保护密码

密码信息被存储在aspnet_Membership表中。SqlMembershipProvider 允许我们在数据库中存储密码时使用以下三种技术之一:

  • Clear – 密码在数据库中以明文形式存储。I 强烈不建议使用该选项。如果数据库受到攻击– 可能是某个找到后门的黑客或心怀不满的员工访问数据库– 每个用户的凭证就一览无余了。
  • Hashed – 通过单向哈希算法将密码打乱,并随机生成salt 值。哈希值(以及 salt )存储在数据库中。
  • Encrypted – 数据库中存储的是加密后的密码。

使用的密码存储技术取决于Web.config 中的SqlMembershipProvider 设置。我们将在步骤4 中探讨定制SqlMembershipProvider 设置。默认采用的是存储密码的哈希值。

负责存储密码的列是PasswordPasswordFormatPasswordSaltPasswordFormat是一个类型为int的字段,它的值指示存储密码时使用的技术:0表示Clear;1 表示 Hashed;2 表示Encrypted。PasswordSalt 是一个随机生成的字符串,与使用的密码存储技术无关;计算密码的哈希值时才会用到PasswordSalt 的值。最后,Password列包含的是实际的密码数据,可能是明文的密码,或是密码哈希值,或是加密的密码。

表1 说明了采用不同存储技术存储密码“MySecret!” 时这三列的值。

存储技术

Password

PasswordFormat

PasswordSalt

Clear

MySecret!

0

tTnkPlesqissc2y2SMEygA==

Hashed

2oXm6sZHWbTHFgjgkGQsc2Ec9ZM=

1

wFgjUfhdUFOCKQiI61vtiQ==

Encrypted

62RZgDvhxykkqsMchZ0Yly7HS6onhpaoCYaRxV8g0F4CW56OXUU3e7Inza9j9BKp

2

LSRzhGS/aa/oqAXGLHJNBw==

表1:存储密码“MySecret!” 时与密码相关的字段示例值

注意:SqlMembershipProvider 使用的具体加密或哈希算法由<machineKey>元素中的设置确定。我们在《表单身份验证配置和高级主题 》教程的步骤 3中讨论了该配置元素。

存储角色和角色关联

Roles 框架允许开发人员定义一系列的角色,并指定哪些用户属于哪些角色。该信息存储在数据库的两个表中:aspnet_Rolesaspnet_UsersInRolesaspnet_Roles表中的每条记录表示特定应用程序的一个角色。与aspnet_Users表类似,aspnet_Roles表也有三个列与我们的讨论有关:

  • RoleId
  • RoleName
  • ApplicationId

RoleId 是主键(类型为uniqueidentifier)。RoleName的类型为nvarchar(256)ApplicationId将用户帐户与aspnet_Applications中的特定应用程序链接起来。在RoleNameApplicationId列上有一个复合UNIQUE约束,确保在给定应用程序中每个角色的名称都是惟一的。

aspnet_UsersInRoles 表作为用户和角色之间的映射。它只有两个列– UserIdRoleId–它们一起构成复合主键。

步骤4:指定提供者并定制其设置

所有支持提供者模式的框架,如Membership 和 Roles 框架,其自身是不管实现细节的,而是委托给一个提供者类负责。在Membership 框架中,Membership类定义管理用户帐户的API,但它并不直接与任何用户存储交互。相反,Membership类的方法将请求扔给配置的提供者– 我们将使用SqlMembershipProvider。我们调用Membership类的一个方法时,Membership 框架是如何知道将调用委托给SqlMembershipProvider 的呢?

Membership 类有一个Providers 属性,它包含对Membership 框架可用的所有已注册提供者类的引用。每一个注册的提供者都有一个相关联的名称和类型。名称以友好方式引用Providers 集合中的某个提供者,类型标识提供者类。此外,每个注册的提供者可能都包含配置设置。Membership 框架的配置设置包括passwordFormatrequiresUniqueEmail,以及很多其它项。有关SqlMembershipProvider 使用的配置设置全表,参见表2。

Providers 属性的内容是通过web 应用程序的配置设置指定的。默认情况下,所有的web 应用程序都有一个类型为SqlMembershipProvider,名称为AspNetSqlMembershipProvider的提供者。该默认Membership 提供者是在machine.config(位于%WINDIR%\Microsoft.Net\Framework\v2.0.50727\CONFIG )中注册的:

<membership>
     <providers>
          <add name="AspNetSqlMembershipProvider"
               type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
               connectionStringName="LocalSqlServer"
               enablePasswordRetrieval="false"
               enablePasswordReset="true"
               requiresQuestionAndAnswer="true"
               applicationName="/"
               requiresUniqueEmail="false"
               passwordFormat="Hashed"
               maxInvalidPasswordAttempts="5"
               minRequiredPasswordLength="7"
               minRequiredNonalphanumericCharacters="1"
               passwordAttemptWindow="10"
               passwordStrengthRegularExpression=""/>
     </providers> 
</membership>

如上述的标记所示,<membership> 元素定义 Membership 框架的配置设置,而<providers> 子元素指定注册的提供者。使用<add><remove> 元素添加或删除提供者;使用<clear> 元素删除所有当前注册的提供者。如上述的标记所示,machine.config添加一个类型为SqlMembershipProvider的名称为AspNetSqlMembershipProvider的提供者。

nametype属性之外,<add>元素还包含定义各种配置设置值的属性。表2 列出了可用的与SqlMembershipProvider 有关的配置设置,以及对各个设置的说明。

注意: 表 2中注明的所有默认值都参考了SqlMembershipProvider 类中定义的默认值。我们注意到,AspNetSqlMembershipProvider 中的配置设置并不都与SqlMembershipProvider 类的默认值一致。比如,如果没在Membership 提供者中指定,requiresUniqueEmail 设置的默认值为true。然而,AspNetSqlMembershipProvider通过明确指定false值来覆盖了该默认值。

设置

说明

ApplicationName

我们知道,Membership 框架允许将一个用户存储分区到多个应用程序中。该设置指示Membership 提供者使用的应用程序分区的名称。如果没有明确指定该值,在运行时,将它设置为应用程序的虚拟根路径的值。

commandTimeout

指定 SQL 命令的超时值(单位为秒)。默认值为30。

connectionStringName

 <connectionStrings>元素中的连接字符串名称,用于连接到用户存储数据库。该值是必需的。

description

提供已注册提供者的友好说明。

enablePasswordRetrieval

指定用户是否可以找回已忘记的密码。 默认值为 false

enablePasswordReset

指示是否允许用户重置密码。默认值为true

maxInvalidPasswordAttempts

在用户被锁定之前,某给定用户在指定的passwordAttemptWindow 期间可以发生的最大登录失败尝试次数。默认值为5。

minRequiredNonalphanumericCharacters

用户密码中必须出现的非字母数字字符的最少数目。该值必须在0 到 128 之间;默认值为1。

minRequiredPasswordLength

密码中所需字符的最少数。该值必须在0 到 128 之间;默认值为7。

name

已注册提供者的名称。该值是必需的。

passwordAttemptWindow

跟踪失败登录尝试的分钟数。如果用户在该指定的窗口提供无效登录凭证maxInvalidPasswordAttempts次,则锁定他们。默认值为10。

PasswordFormat

密码存储格式:Clear 、Hashed 或Encrypted。默认值为Hashed

passwordStrengthRegularExpression

如果提供,在创建新帐户或更改密码时,该正则表达式用于评价用户所选密码的强度。默认值为空字符串。

requiresQuestionAndAnswer

指定用户在找回或重置密码时是否必须回答其安全性问题。 默认值为 true

requiresUniqueEmail

指示给定应用程序分区中的所有用户帐户是否必须有惟一的电子邮箱。默认 值为 true

type

指定提供者的类型。该值是必需的。

表2: Membership 和SqlMembershipProvider 配置设置

除了AspNetSqlMembershipProvider以外,通过在Web.config 文件中添加类似的标记,也可针对每个应用程序注册其它的Membership 提供者。

注意:Roles 框架也采用差不多相同的方式:machine.config中有一个默认注册的角色提供者,可在Web.config中针对每个应用程序定制已注册提供者。我们将在后面的教程中详细探讨Roles 框架及其配置标记。

定制SqlMembershipProvider 设置

默认的SqlMembershipProvider (AspNetSqlMembershipProvider)将其connectionStringName属性设置为LocalSqlServer。与AspNetSqlMembershipProvider提供者类似,在machine.config 中定义连接字符串名称LocalSqlServer

<connectionStrings> 
     <add name="LocalSqlServer" 
     connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" 
     providerName="System.Data.SqlClient"/> 
</connectionStrings>

正如您看到的那样,该连接字符串定义的是一个位于“|DataDirectory|aspnetdb.mdf� 的 SQL 2005 Express Edition 数据库。字符串“|DataDirectory|�在运行时被翻译成指向~/App_Data/ 目录,因此数据库路径“|DataDirectory|aspnetdb.mdf" 被翻译成~/App_Data/aspnet.mdf

如果我们不在应用程序的Web.config文件中指定任何Membership 提供者信息,则应用程序使用默认注册的Membership 提供者AspNetSqlMembershipProvider。如果~/App_Data/aspnet.mdf 数据库不存在,则ASP.NET 运行时将自动创建它并添加到应用程序服务架构。然而,我们不想使用aspnet.mdf数据库,而想使用我们在步骤2 中创建的SecurityTutorials.mdf 数据库。可通过以下两种方式之一来完成此修改:

  • 在Web.config中指定LocalSqlServer连接字符串的值。通过覆盖 Web.config  中的 LocalSqlServer 连接字符串名称的值,我们可以使用默认注册的Membership 提供者 (AspNetSqlMembershipProvider) ,并让它正确地使用 SecurityTutorials.mdf 数据库。如果您对 AspNetSqlMembershipProvider指定的配置设置满意,该方法就很好。有关该技术的更多信息,参见 Scott Guthrie 的博客文章 Configuring ASP.NET 2.0 Application Services to Use SQL Server 2000 or SQL Server 2005
  • 添加一个新的类型为SqlMembershipProviderdd的已注册提供者,并配置其connectionStringName设置指向SecurityTutorials.mdf数据库。该方法在您想定制除数据库连接字符串的其它配置属性时有用。在我的项目中,我总是使用该方法,因为它既灵活又易读。

在我们添加引用SecurityTutorials.mdf 数据库的新注册提供者之前,我们首先需要在Web.config<connectionStrings>区域中添加相应的连接字符串值。下面的标记添加一个名为SecurityTutorialsConnectionString的新连接字符串,它引用App_Data 文件夹中的SQL Server 2005 Express Edition SecurityTutorials.mdf 数据库。

<configuration>
     <connectionStrings>
          <add name="SecurityTutorialsConnectionString" 
          connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\SecurityTutorials.mdf;
                                        Integrated Security=True;User Instance=True" 
          providerName="System.Data.SqlClient"/> 
     </connectionStrings> 
     <system.web>
          ... Configuration markup  removed for brevity ... 
     </system.web>
</configuration>

注意: 如果您使用的是其它数据库文件,应根据需要更新连接字符串。有关构建正确的连接字符串的更多信息,请参考ConnectionStrings.com

接下来,在Web.config 文件中添加如下的Membership 配置标记。该标记注册一个名为SecurityTutorialsSqlMembershipProvider的新提供者。

<configuration> 
     <connectionStrings>
          <add name="SecurityTutorialsConnectionString" 
          connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\SecurityTutorials.mdf;
          Integrated Security=True;User Instance=True" 
          providerName="System.Data.SqlClient"/>
     </connectionStrings> 
     <system.web>
          <membership defaultProvider="SecurityTutorialsSqlMembershipProvider">
               <providers>
                    <!--Add a customized SqlMembershipProvider --> 
                    <add name="SecurityTutorialsSqlMembershipProvider" 
                    type="System.Web.Security.SqlMembershipProvider"
                    connectionStringName="SecurityTutorialsConnectionString"
                    enablePasswordRetrieval="false"
                    enablePasswordReset="true"
                    requiresQuestionAndAnswer="true"
                    applicationName="SecurityTutorials"
                    requiresUniqueEmail="true"
                    passwordFormat="Hashed"
                    maxInvalidPasswordAttempts="5"
                    minRequiredPasswordLength="7"
                    minRequiredNonalphanumericCharacters="1"
                    passwordAttemptWindow="10"
                    passwordStrengthRegularExpression=""/>
               </providers>
          </membership>
          ... Configuration markup removed for brevity ... 
     </system.web>
</configuration>

上述标记除了注册SecurityTutorialsSqlMembershipProvider提供者之外,还将SecurityTutorialsSqlMembershipProvider定义为默认的提供者(通过<membership>元素中的defaultProvider属性)。我们知道,Membership 框架可以有多个已注册的提供者。因为AspNetSqlMembershipProvidermachine.config 中的第一个注册的提供者,所以,在没有指定其它提供者时,它就是默认的提供者。

目前,我们的应用程序有两个注册的提供者:AspNetSqlMembershipProviderSecurityTutorialsSqlMembershipProvider 。不过,在注册SecurityTutorialsSqlMembershipProvider提供者之前,我们本可以在<add>元素之前添加一个<clear>元素来清除所有以前注册的提供者。这将从注册提供者列表中清除AspNetSqlMembershipProvider,意味着SecurityTutorialsSqlMembershipProvider将是惟一注册的Membership 提供者。如果我们使用该方法,则不必将SecurityTutorialsSqlMembershipProvider标记为默认提供者,因为它是惟一注册的Membership 提供者。有关使用<clear /> 的更多信息,请参见Using <clear /> When Adding Providers

我们注意到,SecurityTutorialsSqlMembershipProviderconnectionStringName设置引用的是刚添加的SecurityTutorialsConnectionString连接字符串名称,且其applicationName 设置已被设为“SecurityTutorials” 值。此外,requiresUniqueEmail设置已被设为true。所有其它配置选项与AspNetSqlMembershipProvider中的值一样。如果您愿意,可随意修改配置。例如,为增强密码强度,您可以要求两个非字母数字的字符,而不是一个,或将密码的长度增加到8 个字符,而不是7个。

注意: 我们知道,Membership 框架允许一个用户存储被分区到多个应用程序。Membership 提供者的applicationName设置指示处理用户存储时提供者使用的应用程序。明确设置applicationName配置设置的值很重要,因为如果没有明确设置applicationName,运行时它会被赋值为web 应用程序的虚拟根路径。只要应用程序的虚拟根路径不变化,这就不会有问题,但如果您将应用程序移到另一个路径,则applicationName设置也会改变。发生这种情况时,Membership 提供者就开始使用与先前不同的应用程序分区。移动之前创建的用户帐户将位于不同的应用程序分区中,而且这些用户将不再能够登录该站点。对这种情况的深入讨论,请参见Always Set the applicationName Property When Configuring ASP.NET 2.0 Membership and Other Providers

小结

到目前为止,我们有一个配置了应用程序服务(SecurityTutorials.mdf) 的数据库,并对我们的web 应用程序进行了配置,使Membership 框架使用我们刚注册的SecurityTutorialsSqlMembershipProvider提供者。该注册提供者的类型为SqlMembershipProvider,其connectionStringName被设为相应的连接字符串(SecurityTutorialsConnectionString),并明确设置了其applicationName 值。

我们现在可以在我们的应用程序中使用Membership 框架了。在下一篇教程中,我们将探讨如何创建新的用户帐户。然后,我们将探讨身份验证用户、执行基于用户的授权以及在数据库中存储与用户相关的其它信息。

快乐编程!

 

下一篇教程