使用更少的代码保证 ASP.NET 应用程序的安全

Michele Leroux Bustamante

Idesign:.NET 设计和业务解决方案

2003 年 10 月

适用于:

Microsoft ASP.NET Whidbey

摘要:了解 ASP.NET Whidbey 及其新的配置工具、控件和组件如何支持一个完整的系统,以对用户进行身份验证和管理受保护资源。(23 页打印页)

下载 ASPNETWhidbeySecuritySample.msi

内容

直观易用的功能

配置界面

拖放安全性

按角色筛选内容

成员身份和角色提供程序

但是,这个程序是可扩展的吗?

结论

本文是在产品的发行版投入生产之前完成的,因此,我们不能保证这里包含的任何细节与发行产品中找到的细节完全一样。文中对产品的描述信息仅限于本文发表时的产品,并且仅用于规划方面的用途。本文的信息随时可能更改,恕不预先通知。

我曾经创建过许多 Microsoft ASP.NET 应用程序,这些应用程序包括:客户端应用程序和原型、我自己不断增长的一些站点、为不能编写代码的家庭和朋友创建的站点,以及为某些文章、演讲和培训课程而编写的代码。我经常发现自己在每个应用程序中都重复了某些工作,其中定义身份验证模型的重复尤为频繁。在几乎所有应用程序的设计中,保护应用程序资源是必要的一部分。ASP.NET 1.x 提供了一种非常简单和安全的基于窗体的身份验证处理,这使得事情变得更加简单,但除了这些工作之外,您仍必须自己做角色管理的工作。如果每设计一个新登录窗体就可以得到 5 美分,那么现在我的口袋中至少已经又多了 10 美元;计算一下,这需要许多窗体呢。即将推出的新版 ASP.NET – 代码名称为 ASP.NET "Whidbey"(根据即将推出的新版 Microsoft Visual Studio .NET 的代号来命名),它提供了许多新的配置工具、控件和组件来支持一个完整的系统,以对用户进行身份验证和管理受保护的资源。这些新功能极为直观易用,即使是您的祖母也可在一天之内构建一个安全的站点。

直观易用的功能

为新的 Web 站点构建身份验证模型的传统方法通常包括如下一些步骤:

搜集保护资源和活动的要求,并定义适用的角色和权限。

设计关系数据库表来存储用户、角色以及相关的权限。

设计登录页面。

编写代码,以对用户进行身份验证并收集相关的角色和权限。

添加配置,以根据角色来保护 Web 资源。

编写代码,以根据角色和权限来控制页面内容。

虽然只是构建几个可重用的组件来封装上述某些重复性工作,您仍会觉得肩上的负担轻松了不少。使用 ASP.NET Whidbey 的新组件,即使没办法完全免去这些工作,但至少也将减少这些工作中的五个步骤。使用新的基于 Web 的管理向导,我将可以自动创建一组表来处理用户、角色和权限。在同一个管理界面中,还可以针对登录、成员身份和角色管理来配置应用程序。我可以在一秒钟内设计出一个登录页面(即,我在 Web 窗体上拖放登录控件所花费的时间),而且不需要编写一行代码来对用户进行身份验证或关联角色,因为这些是自动处理的。根据用户的角色和登录状态的不同,呈现的菜单和页面内容也会有所不同,但同样不需要为其编写任何代码。

是不是有梦想成真的感觉?让我们来看一下它是如何实现的。

配置界面

ASP.NET Whidbey 包含了一种新的基于 Web 的配置工具,它运行在特定应用程序的上下文中,因此可以通过交互的方式修改应用程序自身的 web.config 文件。该工具包含了很多向导,其中一个向导可以引导您通过一些步骤来设置安全选项。使用 Visual Studio "Whidbey" 创建一个新的 Web 站点后,您可以通过如下两种方式来启动配置工具:从 Solution Explorer 选择 ASP.NET Configuration 图标,或者从 Website 菜单中选择 ASP.NET Configuration。

图 1. 从 Solution Explorer 或主菜单中启动基于 Web 的配置实用工具。

1. 从 Solution Explorer 或主菜单中启动基于 Web 的配置实用工具。

用一个查询字符串启动配置 Web 界面,该字符串指出要配置的目标应用程序。我为本文创建了一个名为 MySecureNewsletter 的新的应用程序,并启动了管理界面,如下所示:

剖析业务服务

2. 在我的计算机上启动管理界面的 URL 是http://localhost:10245/ASP.NETWebAdminFiles/default.aspx?applicationPhysicalPath=H:/WebSites/MySecureNewsletter/&applicationUrl=/MySecureNewsletter。

Secutity 选项卡上有一个选项可以用来运行 Security Setup Wizard。对于新的应用程序,应该首先运行该向导。向导界面左侧的面板显示了您将会进行的一系列步骤,并指出了您当前所处的步骤:

安全设置向导利用了 ASP.NET Whidbey 的一些其他的非常酷的功能,例如用于导航的向导控件

3. 安全设置向导利用了 ASP.NET Whidbey 的一些其他的非常酷的功能,例如用于导航的向导控件

此设置过程的步骤非常直观,因此,我只概括说明一下为此示例应用程序选择的一些选项。首先,向导将询问我该站点是 Intranet 站点还是 Internet 站点。前者默认使用 Windows 身份验证;后者(我的选择)将应用程序配置为使用窗体验证。接下来,有一个用于创建存储用户和角色的数据库的选项可供我选择。如果我选择了该选项,此工具将进一步询问是选择创建 Microsoft Access 数据库,还是创建 Microsoft SQL Server? 数据库,然后引导我完成几个附加的步骤。我没有选择该选项,因此系统在应用程序的 /Data 目录下会创建一个默认的 Access 数据库。在 machine.config 文件中, <connectionString> 元素指定了 Access 数据库的默认位置:

    <connectionStrings>          <add name="LocalSqlServer" connectionString="data            source=127.0.0.1;Integrated Security=SSPI" />          <add name="AccessFileName"             connectionString="~/DATA/ASPNetDB.mdb" />    </connectionStrings>

接下来,我启用了应用程序的角色管理。此时,将会创建一个默认的 Access 数据库,其中包含大量表,这些表最终将由新的安全控件和成员身份 API 使用。此时,我可以选择创建角色和用户。创建每个角色时都需要使用一个简单的字符串值,如下图所示:


4. 界面左侧的向导面板显示了当前在设置应用程序安全模型的过程中所处的步骤

为了创建用户,我针对需要为每个用户收集的字段做了一些假设,具体地说,这些字段有用户名、密码、电子邮件、说明以及可选的带有答案的密码问题。如果创建了任何角色,则这些字段还将作为复选框选择提供:


5. 这里输入的电子邮件字段以后将用于与用户交互,例如恢复密码过程。

通过上面这几个简单的步骤,我们已经在 /Data 目录下创建一个新的数据库(文件名为 AspNetDB.mdb),用以存储成员身份信息。刷新 Solution Explorer 后,您还可以看到已创建了一个 web.config 文件,用于启用 <roleManager>设置中的角色管理。这一过程是必需的,因为 machine.config 中默认设置为禁用角色管理。这个新的 web.config 文件类似如下所示:

<?xml version="1.0" encoding="utf-8"?><configuration>    <system.web>        <roleManager enabled="true">            <providers />        </roleManager>    </system.web></configuration>

在上述这几个简短的步骤中,我创建了标准的成员身份和凭据管理数据库,也创建了一些角色和用户,并完成了角色管理所需的 Web 配置,现在我们就可以构建一个安全的应用程序了。

如果您在首次配置时不准备创建角色和用户,您可以随时返回该配置工具以输入或修改配置,但我现在将演示如何构建自己的管理页面。

拖放安全性

至本文的此节结束时,您仍然不需要编写任何代码。我将向您演示如何使用 ASP.NET Whidbey 的新安全控件,来生成一个可行的基于角色的身份验证系统。我将从示例的新闻稿应用程序 MySecureNewsletter 开始。目前,除了使用向导完成的这些步骤之外,还没有生成任何安全模型。顺便提一下,这个应用程序使用了 Whidbey 的新母版页功能,有关该功能的更多信息,请参阅 Master Pages in ASP.NET Whidbey 。在 Solution Explorer 中,您将看到一个 /templates 目录和一个 /arts 目录,前者包含了可重用的用户控件和母版页模板,后者存储了所有支持的图形。根目录中存在一些应用程序页面。


6. 示例应用程序中的所有 *.aspx 页面都将使用母版页作为布局模板。内容页和 Web 窗体页一样,但内容页指定了母版页模板,而且所有内容均放在内容控件中。

登录

在添加了一个名为 login.aspx 的新内容页后,我们就可做一些有趣的事情了。工具箱中有一个 Security 选项卡,其中列出了 ASP.NET Whidbey 中的一些非常酷的、与安全相关的新控件。


7. 已为 ASP.NET Whidbey 重新组织了 Toolbox,并将新的安全控件分组到各自的选项卡上。

我将从刚才拖放到新 login.aspx 页面上的 Login 控件开始,逐个探究这些安全控件:


8. Login 控件提供了一个可交互的设计器界面,用于编辑默认的控件布局。

您可以通过选择其中一个 AutoFormat 选项来为控件的外观选择一种已封装的格式:


9. 目前有两个已封装的格式可用,但如果您有一个应用程序的默认样式表,您也可以通过 Properties 窗口将样式分配给控件的各个元素。

Properties 窗口也提供对控件中各个元素的标签、值和验证错误消息的访问。您也可以自定义登录按钮的外观,并提供一个创建新成员的链接。现在让我们来看一下,使用了可信任样式表和控件的默认选项后,结果会是怎样。控件生成的源代码如下所示:

<asp:login id="Login1" runat="server"></asp:login>

这样,我的登录页面就完成了。由于我已经为应用程序配置了用户和角色,所以只需修改 web.config 文件,将身份验证模式设置为 Forms 即可(由于默认行为是 Windows 身份验证)。同时,为了测试登录进程,我还将拒绝匿名用户:

      <authentication mode="Forms"/><authorization>         <deny users="?" />      </authorization>

我在前面提过,“安全设置向导”将应用程序配置为窗体身份验证,它是通过生成默认数据库来存储凭据,从而完成该配置的。它在 Whidbey Alpha 中没有修改应用程序 web.config 文件中的 <authentication> 设置,以将身份验证模式指定为如列表所示的窗体模式。

现在系统将引导所有匿名用户前往登录页面。由于使用了母版页和样式表,在花了一点时间将登录控件拖动到窗体后,该页面看起来还不算太差劲:


10. 在没有修改任何属性的情况下,Login 控件的默认外观如图中所示,它使用了我的样式表并显示在我的页面模板中。

谁登录了?

如果我输入一个有效的用户名和密码,Log In 按钮将自动对用户进行身份验证,并将其重定向到最初的请求页面。当然,登录以后,习惯上会为用户显示个性化的欢迎页面,并提供一种注销的方式。我将把这两个功能添加到每个页面中出现的 menus.ascx 用户控件。LoginName 控件显示了已验证用户的名称,LoginStatus 控件则提供了一个方便的超级链接,它会根据当前的验证状态在登录和注销操作之间切换。在将这两个新的控件添加到适当位置的 menus.ascx 文件后,其 HTML 源代码如下:

You are currently logged in as: <asp:loginname id="LoginName1"  runat="server"></asp:loginname><asp:loginstatus id="LoginStatus1" runat="server"></asp:loginstatus>

噢,这太粗略了。请看,现在我们有了一个登录页面,在用户登录后可以显示个性化欢迎页面,并且我们还提供了一种用户注销的方式……所有这些都不需要编写代码。


11. 在登录/注销之间切换

LoginName 控件只执行一个任务,即显示已验证用户的名称。默认情况下,LoginStatus 控件自动在登录和注销之间切换,但可以使用模板进一步自定义它。注销的实际进程也由该控件封装。

此个性化欢迎页面唯一的问题是,在登录之前它显示的是一个空白的用户名,因此可能需要编写一些代码对该部分进行控制。不过,我们或许同样可以不用编写代码就可做到。

控制对内容的访问

如果使用的是早期版本的 ASP.NET 来显示当前已验证的用户,我们可能要编写一些代码来访问当前上下文中的用户标识。为了仅在用户身份验证之后才显示这些信息,可能还要编写更多的代码来检查用户的状态。LoginView 控件可能是最有意思的新安全控件之一,因为它使我们可以根据身份验证状态和角色来控制页面内容。为了检验这一点,我向 menu.ascx 文件中添加了一个 LoginView 控件。通过与设计环境进行交互,您可以编辑想要向匿名用户(尚未登录)和已验证用户显示的信息。


12. Common LoginView Tasks 使您可以在视图间进行切换,或者通过单击 Edit Templates 超级链接来开始编辑模板。

您始终可以通过 Source 视图直接修改 HTML。以下代码显示了向 menus.ascx 文件的个性化欢迎部分添加 LoginView 控件时所做的修改:

<asp:loginview id="LoginView1" runat="server">    <anonymoustemplate>        You are not currently logged in.    </anonymoustemplate>    <loggedintemplate>     You are currently logged in as:<asp:loginname id="LoginName1"       runat="server">                </asp:loginname>    </loggedintemplate></asp:loginview>

当用户身份尚未验证时,LoginView 控件显示了 <anonymoustemplate>部分的内容;当用户经过身份验证后,它显示 <loggedintemplate> 部分的内容。这样,我们没有编写任何代码,就利用安全控件向用户提供了登录页面、注销功能、个性化欢迎页面以及根据身份验证状态自定义的页面内容。

什么?忘记了密码?

您可能难以相信,自动进行密码管理是何等的容易!PasswordRecovery 控件提供了一个功能全面的密码恢复系统,它可以根据密码问题查找密码、自动实现重置密码,并通过电子邮件将密码发送给用户的过程。我在应用程序的根目录中创建了一个密码恢复页面,将 PasswordRecovery 控件拖放到该页面后,可以看到如下的画面:


13. Common PasswordRecovery Tasks 使您可以自定义恢复过程中每一阶段的外观。

密码管理涉及大量的活动,所有的这些活动都是可配置的。例如,您可以要求用户创建密码问题和答案,并将其作为密码安全模型的一部分。PasswordRecovery 控件包括一个界面,用于提示用户回答他们自己的密码问题,这个问题是他们在创建自己的帐号时提供的。如下所示,您可以编辑密码恢复中每部分的设置,包括请求用户名、提示密码问题以及完成恢复过程后显示对用户的响应。


14. 给出的密码问题和答案可以通过成员身份提供程序进行配置,该提供程序将在本文后面讨论。

该控件自动重置密码,并将新的密码发送到用户的电子邮件帐户中。生成的电子邮件的属性可以通过控件的公共属性来配置。在示例程序中,我自定义了要发送的电子邮件的主题标题和地址。生成的 HTML 如下所示:

    <asp:passwordrecovery id="Passwordrecovery1" runat="server">        <maildefinition bodyformat="Html" subject="Password Recovery for          MySecureNewsletter" from="mailto:mailadmin@dotnetdashboard.com">        </maildefinition>    </asp:passwordrecovery>

如果正确配置了用于发送电子邮件的 SMTP 服务器,实际上可以收到带有新密码的电子邮件:


15. 您可以为电子邮件提供一个 HTML 模板,这可通过在 Properties 窗口中设置 BodyFilename 和 BodyFormat 属性实现。

在示例中,我使用自己的 SMTP 服务器来测试此功能,但您将在 web.config 文件中看到这个 SMTP 设置的示例:

       <smtpMail            serverName="smtp.mysmtpserver.com"            serverPort="25">        </smtpMail>

这是一个奇妙的功能,为处理密码管理提供了快速的解决方案。但对于大型站点,您可能希望进一步了解组件的结构。例如,如果想要确保生成电子邮件的组件具有可伸缩性,您可能会编写一些代码来控制如何将密码通过电子邮件发送给成员,或者通过提供过期的 Web 页面的链接来显示解密密码。

按角色筛选内容

大多数应用程序依赖角色来控制对资源的访问、信息显示的方式和可允许的活动。前面我创建了很多用户,并使用安全管理工具为其分配了角色。在以前版本的 ASP.NET 中,为了使用这些角色就要编写代码,以便从已验证用户的凭据存储中手动检索角色。LoginView 控件通过配置的成员身份提供程序或成员身份 API 与这些角色进行交互,并支持为任何有效的角色提供内容模板。

假设要在应用程序中添加一组只能由管理员访问的管理页面。如果向标题中添加一个 Admin 菜单项,可能希望只有管理员看到该菜单项。为了实现这一点,将在菜单界面中添加另一个 LoginView 控件。LoginView 控件的一个属性(可通过 Properties 窗口来访问)支持通过对话框界面向 RoleGroups 集合中添加角色列表:

剖析业务服务

16. RoleGroup Collection Editor 要求手动输入角色。您也可以对角色进行分组,以便多个组可以共享相同的模板界面。

在 Design 视图中,LoginView 控件现在将角色列表反映为模板选项:


17. HTML 视图将被更新,以反映您为每个角色设计的所有模板。

从下面的 HTML 源代码中,您可以看到对 Admin 和 Member 角色使用了新的内容模板。在身份验证之前仍将使用 <anonymoustemplate>,但在身份验证之后将使用与某个用户角色匹配的第一个模板。如果没有找到匹配项,则默认将使用 <loggedintemplate> 设置。

<asp:loginview id="lvMenu" runat="server">    <anonymoustemplate>        <asp:loginstatus id="anonLoginStatus" runat="server">        </asp:loginstatus>    </anonymoustemplate>    <rolegroups>        <asp:rolegroup roles="Admin">            <contenttemplate>    <tr>       <td class="OtherTabs">        <asp:hyperlink id="adminHome" runat="server"          navigateurl="~/default.aspx">Home</asp:hyperlink>            &nbsp;|&nbsp;</td>        <td class="OtherTabs">         <asp:hyperlink id="adminAbout" runat="server"           navigateurl="~/about.aspx">About</asp:hyperlink>             &nbsp;|&nbsp;</td>        <td class="OtherTabs">        <asp:hyperlink id="adminAdmin" runat="server"          navigateurl="~/admin/manageMembers.aspx">Admin            </asp:hyperlink>&nbsp;|&nbsp;</td>        <td class="OtherTabs">        <asp:loginstatus id="adminLoginStatus" runat="server">        </asp:loginstatus>        </td>    </tr>            </contenttemplate>        </asp:rolegroup>        <asp:rolegroup roles="Member">            <contenttemplate>    <tr>       <td class="OtherTabs">        <asp:hyperlink id="memberHome" runat="server"           navigateurl="~/default.aspx">Home</asp:hyperlink>            &nbsp;|&nbsp;</td>        <td class="OtherTabs">         <asp:hyperlink id="memberAbout" runat="server"            navigateurl="~/about.aspx">About</asp:hyperlink>             &nbsp;|&nbsp;</td>        <td class="OtherTabs">        <asp:loginstatus id="memberLoginStatus" runat="server">        </asp:loginstatus>        </td>    </tr>            </contenttemplate>        </asp:rolegroup>    </rolegroups>    <loggedintemplate>    <tr>       <td class="OtherTabs">        <asp:hyperlink id="authHome" runat="server"           navigateurl="~/default.aspx">Home</asp:hyperlink>            &nbsp;|&nbsp;</td>        <td class="OtherTabs">         <asp:hyperlink id="authAbout" runat="server"            navigateurl="~/about.aspx">About</asp:hyperlink>             &nbsp;|&nbsp;</td>        <td class="OtherTabs">        <asp:loginstatus id="authLoginStatus" runat="server">        </asp:loginstatus>        </td>    </tr>    </loggedintemplate></asp:loginview>

这些模板将按出现的先后顺序进行分析,并且将把第一个匹配的角色用作该 LoginView 控件的内容。这表明必须注意按适当的顺序放置角色。这个示例程序的结果是,新的 Admin 菜单项将被限制为只向被赋予 Admin 角色的用户显示。

通过指定 <authorization> 规则拒绝或允许特定的角色,我们还可以使用角色来控制对其他资源的访问。可以使用 <location> 标记在 web.config 文件的应用程序级别实现这一点,或通过将 web.config 文件添加到受保护的子目录中来实现。将下面的 <authorization> 设置放到示例程序的 /admin 目录中,并限定为只允许被赋予 Admin 角色的用户访问:

           <authorization>               <allow roles="Admin" />               <deny users="*" />            </authorization>

现在,是创建一些管理页面来管理成员,并根据 ASP.NET Whidbey 提供的成员身份 API 进行编码的时候了。

成员身份和角色提供程序

至今为止,我向您展示的大多数程序都是以使用新的安全控件为基础的,然而,有一些基础组件可以使您直接管理用户和角色。这些组件提供了从数据库访问层提取出来的层。为了进行演示,将在 /admin 目录中创建一个名为 manageMembers.aspx 的新内容页。该页将显示新闻稿成员的列表,并提供一个中心界面用于添加、编辑或删除新闻稿成员。

在页面上拖入了一个 IDataView 控件,以便在其中填充用户列表。Page_Load 事件包含了一些代码,用以通过使用内部的 Membership 对象来检索所有的用户。新的 Membership 类中有一些方法和属性,它们提供了对默认创建的成员身份数据库的直接访问。例如,GetAllUsers() 返回了应用程序的 MembershipUser 对象的集合。下面的代码将该集合转换成可以绑定到 DataView 控件的一种格式(用于 Appha 版本的解决方案,因为该版本中集合不能被绑定):

MembershipUserCollection members = Membership.GetAllUsers ();ArrayList arr = new ArrayList ();foreach (MembershipUser member in members){arr.Add (member);}GridView1.DataSource = arr;GridView1.DataBind ();

在该页面中,用户可以添加、编辑或从列表中删除成员。删除链接仅需执行下面的一行代码:

Membership.Provider.DeleteUser(user);

添加和编辑成员是由创建的另一个新页面 (newMembers.aspx) 来处理的。当添加新成员时,该页收集要添加到 Members 数据库的新成员的必需信息。就新闻稿应用程序而言,将收集新成员的电子邮件地址和密码,仅此而已。但由于数据库既支持用户名,又支持电子邮件地址,所以同时使用电子邮件地址来填充这两个字段。此外,将为新的用户收集角色选项,这表明必须编写代码来动态列出应用程序所有可用的角色。

Page_Load 事件包含一些加载可用角色的代码,这里使用了一个 Repeater 控件来动态生成一个复选框列表(与安全配置向导中的列表类似)。

// From newMember.aspx		<asp:repeater runat="server" id="roleRepeater">                        <itemtemplate>                        <asp:checkbox runat="server" id="chkRole"                           text='<%# Container.DataItem.ToString()%>'                             checked="<%# m_theUser == null ? false :                               Roles.IsUserInRole(m_theUser.Username,                                 Container.DataItem.ToString())%>"/>                        <br/>                        </itemtemplate></asp:repeater>
// From newMember.aspx.csroleRepeater.DataSource = Roles.GetAllRoles ();roleRepeater.DataBind ();

所生成的输入页面如下所示:


18. 您也可以在成员管理进程中添加密码重置、密码更改以及密码问题和答案等功能。

必须手动设计该页面,不过添加新用户所需的代码很少,因为可以再次使用 membership 组件:

Membership.CreateUser(email.Text, pw.Text, email.Text);

我们需要再编写几行代码,以便从 Repeater 控件中提取角色选项,然后使用该用户的提取结果填充角色表。访问角色数据库的代码还是很简单,这次使用了 Roles 组件:

string[] users = {email.Text};string[] addRoles = new string[roleRepeater.Items.Count];string[] remRoles = new string[roleRepeater.Items.Count];int addIndex = 0;int remIndex = 0;foreach (RepeaterItem itm in roleRepeater.Items){CheckBox c = (CheckBox)itm.FindControl ("chkRole");string role = c.Text;if (c.Checked && !Roles.IsUserInRole(users[0], role)) addRoles[addIndex++]=role;else if (!c.Checked && Roles.IsUserInRole(users[0], role))   remRoles[remIndex++]=role;}if (addIndex > 0){string [] theRoles = new string[addIndex];   Array.Copy (addRoles, 0, theRoles, 0, addIndex);   Roles.Provider.AddUsersToRoles (users, theRoles);}if (remIndex > 0){string [] theRoles = new string[remIndex];   Array.Copy (remRoles, 0, theRoles, 0, remIndex);   Roles.Provider.RemoveUsersFromRoles (users, theRoles);}

同一个 newMembers.aspx 页面也用于编辑用户,QueryString 则用来指出当前模式。在编辑模式中,Page_Load 事件将使用用户信息和当前角色来填充界面。Membership 类还提供了一些方法用于查找特定的用户记录,以及更新发生改变的用户记录。如果使用的是明文密码,而且在成员身份提供程序配置设置中启用了密码检索功能,那么下面代码将更新用户的密码更改:

MembershipUser user = Membership.GetUser (email.Text);  user.ChangePassword (user.GetPassword (), this.pw.Text);

默认情况下,GetPassword() 将失败,这是由于要提高安全性,为每个成员身份提供程序安装了 machine.config 设置。此外,经过哈希运算的密码是提供程序默认和建议的方式。并且,由于经过哈希运算的密码是不可检索的,因此您必须从用户界面中收集用户的旧密码,以调用 ChangePassword() 函数。

但是,这个程序是可扩展的吗?

到目前为止,我一直侧重于如何才能轻松地将身份验证和基于角色的访问控制放到一起完整地实现。尽管所有这些已封装的功能已可满足您 80% 的需要,您还是可以相当容易地扩展这个模型。

数据库创建

例如,可以直接通过安全配置向导将数据库创建过程扩展成支持 SQL Server 或其他自定义的 Access 数据库。下面就是一个示例。在执行向导的过程中,如果您选择创建新的数据库,将会看到此画面:

剖析业务服务

19. 安全向导将在您选择的本地或远程数据库中创建默认的一组成员身份管理表。

您可以直接在应用程序的 SQL Server 数据库中创建成员身份表,而不必使用不具有伸缩性的轻量级 Access 数据库。那就是我所说的改进。也许您的祖母无法知道完成这个步骤所需要的数据库名称和凭据,但您的开发小组一定知道。系统将封装已创建的表,以匹配成员身份和角色提供程序(我们刚刚用其实现了上面的功能)的要求,但如果您计划构建自己的提供程序,那就可以使用其他的表设计并跳过这一步。

标识管理

您可以从我编写的、用于构建一些管理功能的代码中发现,对凭据存储的访问是由成员身份和角色提供程序来处理的。System.Web.Security 命名空间现在含有新的 SqlMembershipProvider 组件和 AccessMembershipProvider 组件,以管理它们各自对默认凭据表的数据访问需求。默认情况下,machine.config 文件的 <membership> 元素包含两个提供程序,分别用于 SQL Server 和 Access 数据库。<providers> 部分可用于添加或删除提供程序,它使您可在应用程序级别删除这些默认的提供程序,并配置自己的提供程序。从下面的设置中可以看到,一些预定义的设置直接与向导创建的表结构相关,包括密码加密、密码重置和检索、密码问题和答案要求以及电子邮件字段项的唯一性等设置。这些规则中的每一条规则均通过各自默认的成员身份(或数据库)提供程序来强制执行,这使您可以在创建自己的表和提供程序之前,按照各种方式使用已封装的表结构。您也可以重写每个提供程序使用的连接字符串。

<membership defaultProvider="AspNetAccessProvider"   userIsOnlineTimeWindow="15" >            <providers>                <add name="AspNetSqlProvider"                    type="System.Web.Security.SqlMembershipProvider,                       System.Web, Version=1.2.3400.0, Culture=neutral,                         PublicKeyToken=b03f5f7f11d50a3a"                    connectionStringName="LocalSqlServer"                    enablePasswordRetrieval="false"                    enablePasswordReset="true"                    requiresQuestionAndAnswer="false"                    applicationName="/"                    requiresUniqueEmail="false"                    passwordFormat="Hashed"                    description="Stores and retrieves membership data from                      the local Microsoft SQL Server database"                />                <add name="AspNetAccessProvider"                    type="System.Web.Security.AccessMembershipProvider,                       System.Web, Version=1.2.3400.0, Culture=neutral,                         PublicKeyToken=b03f5f7f11d50a3a"                    connectionStringName="AccessFileName"                    enablePasswordRetrieval="false"                    enablePasswordReset="true"                    requiresQuestionAndAnswer="false"                    applicationName="/"                    requiresUniqueEmail="false"                    passwordFormat="Hashed"                    description="Stores and retrieves membership data from                       the local Microsoft Access database file"                />            </providers>        </membership>

事实上还有另外一个成员身份提供程序组件,即 System.Web.Security.ADMembershipProvider。它可用于对 Active Directory 存储执行前面提及的相同操作,但目前它只是一个内部功能。

<roleManager> 部分的配置设置可以控制使用何种数据存储来访问相关的角色信息。默认情况下有三种配置设置:SqlRoleProvider、AccessRoleProvider 和 WindowsTokenRoleProvider。这些组件的工作是为用户处理所有的角色管理。同样,还是要为 SQL Server 和 Access 创建一组默认的表,然后 WindowsTokenRoleProvider 调用非托管代码来访问为操作系统的凭据存储而定义的角色。

        <roleManager                enabled="false" cacheRolesInCookie="true"                   cookieName=".ASPXROLES" cookieTimeout="30"                cookiePath="/" cookieRequireSSL="false"                   cookieSlidingExpiration="true"                cookieProtection="All"                   defaultProvider="AspNetAccessProvider" >           <providers>               <add  name="AspNetSqlProvider"                  type="System.Web.Security.SqlRoleProvider, System.Web,                    Version=1.2.3400.0, Culture=neutral,                      PublicKeyToken=b03f5f7f11d50a3a"                     connectionStringName="LocalSqlServer"                     applicationName="/"                     description="Stores and retrieves roles data from the                        local Microsoft SQL Server database" />               <add name="WindowsToken"                    type="System.Web.Security.WindowsTokenRoleProvider,                       System.Web, Version=1.2.3400.0, Culture=neutral,                         PublicKeyToken=b03f5f7f11d50a3a"                    description="Retrieves roles data from the Windows                       authenticated token for the request" />                <add name="AspNetAccessProvider"                    type="System.Web.Security.AccessRoleProvider,                       System.Web, Version=1.2.3400.0, Culture=neutral,                         PublicKeyToken=b03f5f7f11d50a3a"                    connectionStringName="AccessFileName"                    applicationName="/"                    description="Stores and retrieves roles data from the                       local Microsoft Access database file" />           </providers>        </roleManager>

尽管该提供程序模型的设计目的主要是为简化 Web 应用程序的窗体身份验证,但它也用于创建并管理用户和角色的任意验证方案,以及执行一些常见的操作,例如重置密码、密码加密和用户验证。

结论

ASP.NET Whidbey 的新组件和结构功能将使您感到惊奇。这些新功能真正吸引您的地方在于:您可以轻易地组成一个完整的应用程序,并且能够非常容易地扩展这些功能,使其适用于需要可伸缩性的企业级应用。特别地,在安全方面,新的模型无需使用 XML 配置文件来开发蹩脚的“演示代码”,从而不会保留未加密的凭据以及增加服务器上的文件访问负载。当截止日期临近时,我们经常冒险发行演示代码,所以为什么不在第一次就开发出正确的代码呢?现在唯一缺少的就是一个可以将我的想法实时转换成代码的心灵感应设备驱动程序了。

关于作者

Michele Leroux Bustamante 是 IDesign Inc 的合伙人,也是 Microsoft 的区域总监,国际 .NET 演讲者协会 (International .NET Speakers Association,INETA) 的成员,此外,他还是一个公开发表作品的撰稿人。在 IDesign,Michele 在 .NET 培训和高端的企业咨询方面展示了她丰富的背景知识。她主要研究 C# 语言、.NET 框架结构、ASP.NET 和 Web 服务,同时也为技术主管提供指导。可以通过 mlb@idesign.net 与她联系,或者访问 IDesign:.NET Design and Business Solutions 以获得更多的信息。还可以访问 .NET Dashboard ,订阅她的《.NET newsletter》月刊。

转到原英文页面



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=577353

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值