18.3.1  为成员建立Web站点

在使用ASP.NET 2.0提供的安全性控件之前,先建立应用程序来使用新的成员服务。具体操作取决于如何使用安全性架构提供的方法。

ASP.NET 2.0默认使用内置的AspNetSqlProvider来存储应用程序的注册用户的信息。另外,为了进行演示,我们使用Forms验证。假定应用程序对公众开放,以用于注册和浏览。如果这是基于内联网的应用程序(即所有的用户都在特定的网络上),就可以使用Windows Integrated Authentication来验证用户的身份。

ASP.NET 2.0提供了一个数据提供程序模型,来处理与多种底层数据库交互所需要的具体管理功能。图18-1是ASP.NET 2.0新成员服务的示意图。

图  18-1

从图中可以看出,与ASP.NET 2.0的其他提供程序模型相同,成员提供程序也可以访问各种底层数据库。在这个图中,有内置的Microsoft SQL Server数据库。也可以建立自己的成员提供程序,以访问其他定制数据库,处理用户凭证。在成员提供程序的上面是一组安全性服务器控件,它们利用提供程序授予的访问权限在身份验证过程中管理用户。

1. 给web.config文件添加<authentication>元素

为了在Web应用程序中给新的成员服务提供Forms验证的支持,首先要在web.config文件中启用该功能。如果没有web.config文件,就创建一个。接着在该文件中添加如程序清单18-1所示的代码部分。

程序清单18-1  给web.config文件添加Forms验证

<?xml version="1.0" encoding="utf-8"?>

<configuration>

    <system.web>

        <authentication mode="Forms" />

    </system.web>

</configuration>

给web.config文件添加<authentication>元素,就打开了使用ASP.NET 2.0提供的成员服务所需要的所有功能。要使用这个元素打开Forms验证,只需给mode属性指定Forms值。这是一个Forms验证示例,mode属性的其他值有Windows、Passport和None。

IIS验证模式包含basic、digest和Integrated Windows Authentication。Passport验证指向Microsoft提供的一个集中式服务,该服务为任意成员站点提供了一个登录和核心配置文件服务。使用Passport是要付费的,最近Microsoft降低了它的费用。

本例中mode属性设置为Forms,所以可以进行下一步,把用户添加到数据库中。此时,还可以对web.config文件进行一些修改,以改变Forms验证系统的行为。下面就介绍这些修改。

2. 给web.config文件添加<forms>元素

使用Forms验证,可以根据用户在基于Web的窗体上输入的凭证,为他们提供访问站点或资源的权限。终端用户尝试访问Web站点时,使用匿名身份进入站点,这是默认的身份验证模式。如果他是匿名的,就会被ASP.NET重定向到特定的登录页面上。终端用户输入了相应的登录信息,通过了身份验证过程后,就给他提供一个HTTP cookie,以便在后续的请求中使用。

在web.config文件的<forms>段中,可以修改Forms验证系统的行为。程序清单18-2列出了Forms验证设置的各种值,说明了可以对web.config文件的<forms>段进行各种修改。

程序清单18-2  修改Forms验证系统的行为

<?xml version="1.0" encoding="utf-8"?>

<configuration>

    <system.web>

        <authentication mode="Forms">

           <forms name=".ASPXAUTH"

                  loginUrl="login.aspx"

                  protection="All"

                  timeout="30"

                  path="/"

                  requireSSL="false"

                  slidingExpiration="true"

                  cookieless="useDeviceProfile" />

        </authentication>

    </system.web>

</configuration>

可以根据需要设置它们,这些选项可以使用的值比这里显示的还要多。如前所述,这些值不是必需的。可以只对成员服务使用程序清单18-1中的值。

程序清单18-2中有一些有趣的设置。在web.config文件中添加一个<forms>元素,可以改变Forms验证系统的工作方式。一定要把<forms>元素嵌套在<authentication>元素中。下面列出了<forms>元素的属性。

●       name:定义在终端用户进行了身份验证后发送给他们的cookie的名称。默认情况,这个cookie的名称是.ASPXAUTH。

●       loginUrl:如果没有找到有效的验证cookie(.ASPXAUTH或其他),就指定重定向HTTP请求的页面位置。它默认设置为login.aspx。

●       protection:指定应用于cookie的保护级别,该cookie在终端用户通过身份验证后存储在他的机器上。其设置包括All、None、Encryption和Validation。应总是使用All。

●       timeout:定义cookie 过期后的时间(分钟)。默认值是30分钟。

●       path: 指定应用程序调用的cookie路径。

●       requireSSL:定义是要求凭证通过加密线路(SSL)发送,还是通过明文发送。

●       slidingExpiration:指定cookie 的超时是否在可变的范围内。默认值是Ture。这表示,终端用户的cookie 在应用程序的最后一个请求发出30分钟(或timeout属性指定的时间)后过期。如果slidingExpiration属性的值设置为False,cookie就在第一个请求发出30分钟后过期。

●       cookieless:指定ASP.NET 处理cookie的方式。其值可以是useDeviceProfile、useCookies、auto和useUri。默认值是useDeviceProfile。这个值根据设备的用户代理检测是否使用了cookie。useCookies要求所有的请求都在cookie中存储凭证。auto会自动检测信息是存储在客户机的cookie上,还是放在URI中(通过先发送一个测试cookie来进行)。最后,useUri强制ASP.NET把信息存储在所有实例的URI上。

打开了Forms验证后,下一步是给Microsoft SQL Server Express Edition数据库ASPNETDB.mdf添加用户。

18.3.2  添加用户

为了给成员服务添加用户,可以把用户注册到Microsoft SQL Server Express Edition数据库中。第一个问题是:数据库在哪里?

Microsoft SQL Server提供程序可以使用专门为成员服务(和其他ASP.NET系统,如角色管理系统)构建的SQL Server Express Edition文件。如果这个文件不存在,ASP.NET就会自动创建它。要创建ASPNETDB.mdf,应使用ASP.NET服务器控件,该控件利用成员服务来强制创建这个文件。如果应用程序需要ASPNETDB.mdf文件,ASP.NET 2.0会在App_Data文件夹中创建它。

有了数据库后,就可以开始给数据库添加用户了。

1. 使用CreateUserWizard服务器控件

利用成员服务的第一个服务器控件是CreateUserWizard。这个控件和本章涉及的其他控件都在Visual Studio 2005工具箱的Login部分。CreateUserWizard控件可以把注册用户放在数据库中,以便以后进行检索。如果应用程序中的页面允许终端用户注册到站点上,并且至少可以从用户那里获得登录和密码,把这些值放在数据库中,这样该终端用户以后就可以使用成员系统登录到应用程序上。

为了更便于完成任务,CreateUserWizard控件能完全控制注册工作的完成。程序清单18-3是这个控件的一个简单示例。

程序清单18-3  允许终端用户注册到站点上

<%@ Page Language="VB" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Creating Users</title>

</head>

<body>

    <form id="form1" runat="server">

        <asp:CreateUserWizard ID="CreateUserWizard1" runat="server"

         BorderWidth="1px" BorderColor="#FFDFAD" BorderStyle="Solid"

         BackColor="#FFFBD6" Font-Names="Verdana">

            <TitleTextStyle Font-Bold="True" BackColor="#990000"

             ForeColor="White"></TitleTextStyle>

        </asp:CreateUserWizard>

    </form>

</body>

</html>

这个页面只使用了CreateUserWizard控件。这个控件可以在Web应用程序上注册终端用户。该CreateUserWizard控件应用了一些样式,但它可以非常简单:

<asp:CreateUserWizard ID="CreateUserWizard1" runat="server">

</asp:CreateUserWizard>

运行代码,窗体上就会显示一个终端用户,如图18-2所示。

图  18-2

这个屏幕图显示了终端用户填充完后的窗体,其中包含用户信息,例如用户名、密码、电子邮件地址和安全性问答部分。单击Create User按钮,就可以把这些用户信息放在数据库中。

通过该控件提供的用户名和密码可以让终端用户通过Login服务器控件注册到应用程序上。CreateUser服务器控件的窗体中还包含一个Confirm Password文本框,以确保密码拼写正确。包含电子邮件地址是为了在终端用户忘记他的登录凭证时,把该凭证通过电子邮件发送给他。安全性问答部分用于在修改凭证或用户信息前,验证终端用户的身份。

单击这个窗体上的Create User按钮后,就会让终端用户确认要存储的信息,如图18-3所示。

图  18-3

2. 查看用户保存在什么地方

使用CreateUserWizard控件给成员服务添加了用户后,就要看看这些信息存储在什么地方。如果使用Visual Studio创建存储用户信息的Microsoft SQL Server Express Edition文件,则该文件会在上面的例子运行时创建,得到的窗体如图18-3所示。例子运行完后,可以单击Solution Explorer上的Refresh按钮查找ASPNETDB.MDF文件,它位于项目的App_Data文件夹下。这个文件包含许多不同的表,这里只对aspnet_Membership表感兴趣。

在Database Explorer中右击aspnet_Membership表,选择Show Table Data,打开该表,输入的用户就会显示在系统中,如图18-4所示。

这个表中的用户密码没有存储为明文,而是进行了散列。在用户登录到使用ASP.NET 2.0成员服务的应用程序上时,他的密码会被散列,并与存储在数据库中的散列密码进行比较。如果两个散列字符串不相同,密码就不匹配。存储明文密码是有安全风险的,所以千万不要这么做,以规避风险。

在ASP.NET 2.0中使用密码要注意:如果因为密码错误而不能输入用户,可能是因为ASP.NET默认要求使用强密码。输入到系统中的所有密码都至少要有7个字符,其中至少包含一个非数字和字母的字符(例如[ ], !, @, #, $)。这种组合的密码示例如下:

Bevjen7777$

图  18-4

尽管这类密码比较安全,但像这样的密码有时很难记住。实际上,可以改变成员提供程序的工作方式,在web.config文件中重新设置它,使之不要求这么复杂的密码。如程序清单18-4所示。

程序清单18-4  在web.config文件中修改成员提供程序

<configuration>

   <system.web>

      <membership>

         <providers>

            <clear />

            <add name="AspNetSqlMembershipProvider"

             type="System.Web.Security.SqlMembershipProvider, System.Web,

             Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

             connectionStringName="LocalSqlServer"

             requiresQuestionAndAnswer="false"

             requiresUniqueEmail="true"

             passwordFormat="Hashed"

             minRequiredNonalphanumericCharacters="0"

             minRequiredPasswordLength="3" />

         </providers>

      </membership>

   </system.web>

</configuration>

在这个例子中,重新设置了SQL Server的成员提供程序,使之不需要密码包含非数字和字母的字符,而且允许密码只有3个字符。为此,使用minRequiredNonalphanumeric Characters和minRequiredPasswordLength属性。之后,就可以在配置设置中用这些密码规则创建用户了。成员提供程序的修改详见本章后面的内容。

3. 使用CreateUserWizard控件

使用CreateUserWizard控件时,应注意ContinueButtonClick和CreatedUser事件。用户成功创建后,单击第二个页面上的Continue按钮,就会触发ContinueButtonClick事件,如程序清单18-5所示。

程序清单18-5  ContinueButtonClick事件

VB

Protected Sub CreateUserWizard1_ContinueButtonClick(ByVal sender As Object, _

   ByVal e As System.EventArgs)

      Response.Redirect("Default.aspx")

End Sub

C#

protected void CreateUserWizard1_ContinueButtonClick(object sender, EventArgs e)

{

   Response.Redirect("Default.aspx");

}

在这个例子中,通过CreateUserWizard控件提供的窗体把用户添加到成员服务中后,该用户就可以单击Continue按钮,重定向到应用程序的另一个页面中。这是使用简单的Response.Redirect语句实现的。在使用这个事件时,必须给<asp:CreateUserWizard>控件添加OnContinueButtonClick=“CreateUserWizard1_ContinueButtonClick”。

在数据库中成功创建一个用户时,就会触发CreateUser事件。这个事件的用法如程序清单18-6所示。

程序清单18-6  CreateUser 事件

VB

Protected Sub CreateUserWizard1_CreateUser(ByVal sender As Object, _

   ByVal e As System.EventArgs)

      ' Code here

End Sub

C#

protected void CreateUserWizard1_CreateUser(object sender, EventArgs e)

{

   // Code here

}

如果希望在用户注册到服务中时执行其他操作,就可以使用这个事件。

4. 在注册过程中合并个性化属性

在第17章对个性化功能的介绍中,很容易使用ASP.NET 2.0中新的个性化管理系统,存储用户特定的信息。CreateUserWizard控件提供的注册过程非常适合于从用户处获取这些信息,来直接存储在个性化系统中。该获取过程可以放在代码中。

如上一章所述,首先是在应用程序的web.config文件中定义一些个性化信息,如程序清单18-7所示。

程序清单18-7  在web.config文件中创建个性化属性

<configuration>

  <system.web>

     <profile>

        <properties>

           <add name="FirstName" />

           <add name="LastName" />

           <add name="LastVisited" />

           <add name="Age" />

           <add name="Member" />

        </properties>

      </profile>

  </system.web>

</configuration>

在web.config文件中定义了这些属性后,就可以使用它们在ASP.NET成员系统中创建用户了。使用CreateUserWizard控件可以创建一个过程,该过程的第一步要求用户输入他的用户名和密码,第二步输入一些自定义的个性化信息。程序清单18-8显示了完成该任务的CreateUserWizard控件。

程序清单18-8  使用个性化属性和CreateUserWizard控件

VB

<%@ Page Language="VB" %>

<script runat="server">

    Protected Sub CreateUserWizard1_CreatedUser(ByVal sender As Object, _

       ByVal e As System.EventArgs)

        Dim pc As ProfileCommon = New ProfileCommon()

        Pc.Initialize(CreateUserWizard1.UserName.ToString(), True)

        pc.FirstName = Firstname.Text

        pc.LastName = Lastname.Text

        pc.Age = Age.Text

        pc.Save()

    End Sub

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head id="Head1" runat="server">

    <title>Creating Users with Personalization</title>

</head>

<body>

    <form id="form1" runat="server">

        <asp:CreateUserWizard ID="CreateUserWizard1" Runat="server" 

         BorderWidth="1px" BorderColor="#FFDFAD" BorderStyle="Solid"

         BackColor="#FFFBD6" Font-Names="Verdana"

         LoginCreatedUser="true" OnCreatedUser="CreateUserWizard1_CreatedUser" >

            <WizardSteps>

                <asp:WizardStep ID="WizardStep1" Runat="server"

                 Title="Additional Information" StepType="Start">

                    <table width="100%"><tr><td>

                    Firstname: </td><td>

                    <asp:TextBox ID="Firstname" Runat="server"></asp:TextBox>

                    </td></tr><tr><td>

                    Lastname: </td><td>

                    <asp:TextBox ID="Lastname" Runat="server"></asp:TextBox>

                    </td></tr><tr><td>

                    Age: </td><td>

                    <asp:TextBox ID="Age" Runat="server"></asp:TextBox>

                    </td></tr></table>

                </asp:WizardStep>

                <asp:CreateUserWizardStep Runat="server"

                 Title="Sign Up for Your New Account">

                </asp:CreateUserWizardStep>

                <asp:CompleteWizardStep Runat="server" Title="Complete">

                </asp:CompleteWizardStep>

            </WizardSteps>

            <StepStyle BorderColor="#FFDFAD" Font-Names="Verdana"

             BackColor="#FFFBD6" BorderStyle="Solid"

             BorderWidth="1px"></StepStyle>

            <TitleTextStyle Font-Bold="True" BackColor="#990000"

             ForeColor="White"></TitleTextStyle>

        </asp:CreateUserWizard>

    </form>

</body>

</html>

C#

<%@ Page Language="C#" %>

<script runat="server">

    protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)

    {

        ProfileCommon pc = new ProfileCommon();

        pc.Initialize(CreateUserWizard1.UserName.ToString(), true);

        pc.FirstName = Firstname.Text;

        pc.LastName = Lastname.Text;

        pc.Age = Age.Text;

        pc.Save();

    }

</script>

按照CreateUserWizard控件的默认实例定义的那样,对标准注册过程进行这些修改后,注册系统就包含了使用ProfileCommon对象存储属性的请求。然后用ProfileCommon. Initialize()方法初始化当前用户的属性值。接着通过ProfileCommon对象对配置属性进行强类型化的访问,以设置属性值。完成后,用Save()方法结束该过程。

可以在CreateUserWizard控件中使用<WizardSteps>元素定义一个定制的步骤。在这个元素中,可以利用所选的任何方式,构建一系列注册步骤。在<WizardSteps>块中,定义了3个步骤,如程序清单18-8所示。第一步是定制步骤,用<asp:WizardStep>控件请求终端用户的个性化属性。在<asp:Wizard Step>控件中,设置了一个表,创建了一个定制窗体。

程序清单18-7中定义了另外两步:使用<asp:CreateUserWizardStep>控件创建用户;使用<asp:CompleteWizardStep>控件确认新用户的创建。这些步骤的顺序就是它们显示给终端用户的顺序。

以希望的方式创建这些步骤后,就可以使用CreateUserWizard控件的CreatedUser事件存储定制属性:

    Protected Sub CreateUserWizard1_CreatedUser(ByVal sender As Object, _

       ByVal e As System.EventArgs)

        Dim pc As ProfileCommon = New ProfileCommon()

        pc.Initialize(CreateUserWizard1.UserName.ToString(), True)

        pc.FirstName = Firstname.Text

        pc.LastName = Lastname.Text

        pc.Age = Age.Text

        pc.Save()

    End Sub

不仅可以在一个步骤中请求用户输入个人信息,还可以把这些项合并到<asp:Create UserWizardStep>步骤中。一种简单的方法是切换到页面的设计视图上,打开CreateUserWizard控件的智能标记。然后单击Customize Create User Step链接,如图18-5所示。

图  18-5

单击Customize Create User Step,会在<asp:CreateUserWizardStep>控件的一个新块<ContentTemplate>中详细列出这一步的内容。在<ContentTemplate>元素中,使用一个完全默认的窗体来创建新用户。此时,可以自由修改该窗体,添加自己的块,请求终端用户输入其个人信息。在这个详细窗体中,也可以删除数据项。例如,如果不想请求用户输入安全性问答,就可以从窗体中删除这两个项(必须在成员提供程序定义中禁用问答请求)。通过修改这个默认窗体,可以为终端用户完全定制注册过程,如图18-6所示。

图  18-6

5. 编程添加用户

不仅可以使用服务器控件给成员服务注册或添加新用户,ASP.NET 2.0还提供了一个Membership API来编程执行这个任务。这非常适合于创建自己的机制,将用户添加到服务中,或者修改用ASP.NET 1.0/1.1创建的Web应用程序。

Membership API包含将用户添加到服务中的CreateUser方法,该方法有4种不同的签名:

Membership.CreateUser(username As String, password As String)

Membership.CreateUser(username As String, password As String,

   email As String)

Membership.CreateUser(username As String, password As String,

   email As String, passwordQuestion As String,

   passwordAnswer As String, isApproved As Boolean,

   ByRef status As System.Web.Security.MembershipCreateStatus)

Membership.CreateUser(username As String, password As String,

   email As String, passwordQuestion As String,

   passwordAnswer As String, isApproved As Boolean, providerUserKey As Object

   ByRef status As System.Web.Security.MembershipCreateStatus)

可以使用这个方法创建用户。这个方法的优点是,不需要创建Membership类的实例,可以直接使用它。CreateUser方法的简单用法如程序清单18-9所示。

程序清单18-9  编程创建用户

VB

<%@ Page Language="VB" %>

<script runat="server">

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)

   Try

      Membership.CreateUser(TextBox1.Text, TextBox2.Text)

      Label1.Text = "Successfully created user " & TextBox1.Text

   Catch ex As MembershipCreateUserException

      Label1.Text = "Error: " & ex.ToString()

   End Try

End Sub

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Creating a User</title>

</head>

<body>

    <form id="form1" runat="server">

        <h1>Create User</h1>

        <p>Username<br />

            <asp:TextBox ID="TextBox1" Runat="server"></asp:TextBox>

        </p>

        <p>Password<br />

            <asp:TextBox ID="TextBox2" Runat="server"

             TextMode="Password"></asp:TextBox>

        </p>

        <p>

            <asp:Button ID="Button1" Runat="server" Text="Create User"

             OnClick="Button1_Click" />

        </p>

        <p>

            <asp:Label ID="Label1" Runat="server"></asp:Label>

        </p>

    </form>

</body>

</html>

C#

<%@ Page Language="C#" %>

<script runat="server">

    protected void Button1_Click(object sender, EventArgs e)

    {

        try

        {

            Membership.CreateUser(TextBox1.Text.ToString(),

               TextBox2.Text.ToString());

            Label1.Text = "Successfully created user " + TextBox1.Text;

        }

        catch (MembershipCreateUserException ex)

        {

            Label1.Text = "Error: " + ex.ToString();

        }

    }

</script>

使用CreateUserWizard控件或Membership API中的CreateUser方法,可以相当方便地为Web应用程序创建用户。这个功能在过去的ASP.NET 1.0/1.1中也有,但比较麻烦。现在有了ASP.NET 2.0,就可以用一个控件或一行代码创建用户了。

在这行代码中,如果用CreateUser方法创建用户时出了问题,就会抛出MembershipCreate UserException异常。在这个例子中,异常会写到屏幕的一个Label服务器控件上。将异常写入屏幕的一个示例如下所示:

Error: System.Web.Security.MembershipCreateUserException: The password-

answer supplied is invalid. At System.Web.Security.Membership.CreateUser

(String username, String password, String email) at System.Web.Security.

Membership.CreateUser(String username, String password) at ASP.default2_

aspx.Button1_Click(Object sender, EventArgs e) in c:\Documents and Settings\

BillEvjen\My Documents\Visual Studio 2005\WebSites\Membershio\Default2.

aspx:line 10

这些信息最好不要显示给终端用户,而应给他们返回一个比较简单的消息,其构造如下所示:

Label1.Text = "Error: " & ex.Messgae.ToString();

这会得到如下简单结果:

Error: The password-answer supplied is invalid.

还可以用MembershipCreateUserException异常捕获特定的错误,并返回合适的消息,如程序清单18-10所示。

程序清单18-10  捕获特定的MembershipCreateUserException值

VB

<%@ Page Language="VB" %>

<script runat="server">

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)

   Try

      Membership.CreateUser(TextBox1.Text, TextBox2.Text)

      Label1.Text = "Successfully created user " & TextBox1.Text

   Catch ex As MembershipCreateUserException

      Select Case ex.StatusCode

        Case MembershipCreateStatus.DuplicateEmail

      Label1.Text = "You have supplied a duplicate email address. "

        Case MembershipCreateStatus.DuplicateUserName

      Label1.Text = "You have supplied a duplicate username. "

        Case MembershipCreateStatus.InvalidEmail

      Label1.Text = "You have not supplied a proper email address. "

        Case Else

Label1.Text = "Error: " & ex.Messgae.ToString()

   End Select

   End Try

End Sub

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head id="Head1" runat="server">

    <title>Creating a User</title>

</head>

<body>

    <form id="form1" runat="server">

        <h1>Create User</h1>

        <p>Username<br />

            <asp:TextBox ID="TextBox1" Runat="server"></asp:TextBox>

        </p>

        <p>Password<br />

            <asp:TextBox ID="TextBox2" Runat="server"

             TextMode="Password"></asp:TextBox>

        </p>

        <p>

            <asp:Button ID="Button1" Runat="server" Text="Create User"

             OnClick="Button1_Click" />

        </p>

        <p>

            <asp:Label ID="Label1" Runat="server"></asp:Label>

        </p>

    </form>

</body>

</html>

C#

<%@ Page Language="C#" %>

<script runat="server">

    protected void Button1_Click(object sender, EventArgs e)

    {

        try

        {

            Membership.CreateUser(TextBox1.Text, TextBox2.Text);

            Label1.Text = "Successfully created user " + TextBox1.Text;

        }

        catch (MembershipCreateUserException ex)

        {

            switch(ex.StatusCode)

            {

      case MembershipCreateStatus.DuplicateEmail:

        Label1.Text = "You have supplied a duplicate email address. ";

break;

      case MembershipCreateStatus.DuplicateUserName:

         Label1.Text = "You have supplied a duplicate username.";

break;

      case MembershipCreateStatus.InvalidEmail:

     Label1.Text = "You have not supplied a proper email address.";

     break;

      default:

Label1.Text = "Error: " + ex.ToString();

break;

}

        }

    }

</script>

在这个例子中,可以在CreateUser过程中查找特定的错误。这里只查找了3个特定的项,但错误代码列表可以包括如下内容:

●       MembershipCreateStstus.DuplicateEmail

●       MembershipCreateStstus.DuplicateProviderUserKey

●       MembershipCreateStstus.DuplicateUserName

●       MembershipCreateStstus.InvalidAnswer

●       MembershipCreateStstus.InvalidEmail

●       MembershipCreateStstus.InvalidPassword

●       MembershipCreateStstus.InvalidProviderUserKey

●       MembershipCreateStstus.InvalidQuestion

●       MembershipCreateStstus.InvalidUserName

●       MembershipCreateStstus.ProviderError

●       MembershipCreateStstus.Success

●       MembershipCreateStstus.UserRejected

除了定义接下来的操作,给用户发送较好的错误报告之外,还可以使用这些事件执行任何需要的操作。

6. 修改用户注册到应用程序中的方式

我们要确定用户如何注册到应用程序中,以及所选的成员提供程序要求他们输入什么信息。在machine.config文件中建立了一个默认的成员提供程序及其应用的设置。如果打开服务器上的machine.config文件,就会看到如程序清单18-11所示的代码。

程序清单18-11  machine.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"

       passwordAttemptWindow="10"

       passwordStrengthRegularExpression="" />

   </providers>

</membership>

machine.config文件的这个部分显示了ASP.NET 2.0中的默认成员提供程序AspNetSqlProvider。如果要添加其他成员提供程序,并在服务器上使用,就应把提供程序添加到machine.config文件的这个<membership>部分。如果仅将之用于某个应用程序实例,就可以把它们添加到应用程序的web.config文件中。

AspNetSqlMembershipProvider定义的重要属性包括enablePasswordRetrieval、enable PasswordReset、requiresQuestionAndAnswer、requiresUniqueEmail和PasswordFormat。表18-1定义了这些属性。

表  18-1

属    性

说    明

enablePasswordRetrieval

确定提供程序是否支持密码的获取。这个属性带一个布尔值,其默认值是False。它设置为False时,不能检索密码,但可以用一个新的随机密码替代

enablePasswordReset

确定提供程序是否支持密码的重置。这个属性带一个布尔值,其默认值是True。

requiresQuestionAndAnswer

在创建用户时,指定提供程序是否需要问答组合。这个属性带一个布尔值,其默认值是False

requiresUniqueEmail

在创建用户时,指定提供程序是否需要指定唯一的电子邮件。这个属性带一个布尔值,其默认值是False。它设置为True时,可以把唯一的电子邮件地址输入到数据库中

passwordFormat

定义密码存储到数据库中的格式。其值可以是Hashed、Clear和Encrypted ,其默认值是Hashed。散列密码使用SHA1,而加密的密码使用Triple-DES加密方式

除了这些在machine.config文件中定义的项之外,还可以在web.config文件中重新定义它们(这会重写machine.config文件中的设置)。

18.3.3  请求凭证

使用ASP.NET 2.0提供的新成员服务,允许用户访问Web应用程序之后,就可以给这些用户提供登录到站点上的方式。这不需要我们做什么工作。在学习让用户访问应用程序的控件之前,应对web.config文件进行一些修改。

1. 用<authorization>元素禁用访问功能

在通过添加<authorization>和<forms>元素(程序清单18-1和18-2),对web.config文件进行修改之后,Web应用程序就可以由浏览应用程序中任意页面的每个用户访问了。为了禁用访问功能,必须拒绝未验证的用户访问站点的页面。

拒绝未验证的用户访问站点的示例如程序清单18-12所示。

程序清单18-12  拒绝未验证的用户

<?xml version="1.0" encoding="utf-8"?>

<configuration>

    <system.web>

        <authentication mode="Forms" />

        <authorization>

           <deny users="?" />

        </authorization>

    </system.web>

</configuration>

使用<authentication>和<deny>元素,可以拒绝指定的用户访问Web应用程序,或者(如本例所示)简单地拒绝所有未验证的用户(这就是问号的含义)。

除验证用户之外的所有人都会被拒绝访问站点,下面就要使应用程序的访问者成为验证用户。为此,使用Login服务器控件。

2. 使用Login服务器控件

Login服务器控件通过允许未验证的用户提供能在某种数据库中通过验证的登录凭证,把他们转变为验证用户。在前面的例子中,把Microsoft SQL Server Express Edition用作数据库,还可以使用Microsoft SQL Server的完全版本,如Microsoft SQL Server 7.0、2000或2005。

使用Login控件的第一步是创建一个新的Web页面Login.aspx,这是重定向未验证用户,以获得其凭证的默认页面。在web.config文件中修改<forms>元素的loginUrl属性值,就可以改变这种情况。

Login.aspx页面只需要一个<asp:Login>控件,就可以获取把终端用户变成验证用户所需的所有信息,如程序清单18-13所示。

程序清单18-13  使用Login控件为终端用户提供登录

<%@ Page Language="VB" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Login Page</title>

</head>

<body>

    <form id="form1" runat="server">

        <asp:Login ID="Login1" Runat="server">

        </asp:Login>

    </form>

</body>

</html>

在这里建立的页面中,如果未验证用户单击了应用程序中的另一个页面,他就会重定向到Login.aspx页面。可以在浏览器的地址栏中看到ASP.NET跟踪URL中位置的情况:

http://localhost:18436/Membership/login.aspx?ReturnUrl=%2fMembership%2f

Default.aspx

使用Login控件的登录页面如图18-7所示。

图  18-7

在这个图中,Login控件请求用户输入用户名和密码。复选框允许把cookie存储在客户机上。这个cookie可以让终端用户绕过以后的登录过程。把Login控件的DisplayRememberMe属性设置为False,可以删除该复选框和用于记住用户的相关文本。

除了DisplayRememberMe属性之外,还可以使用Login控件的RememberMeText和RememberMeSet属性。RememberMeText属性很容易理解,因为它的值只定义了复选框旁边的文本。但RememberMeSet属性比较有趣,这个属性带一个布尔值(默认为False),指定用户使用Login控件登录后,是否在客户机上设置一个永久的cookie。如果该属性设置为True,而DisplayRememberMe属性也设置为True,在浏览器中生成Login控件时,复选框就默认选中。如果DisplayRememberMe属性设置为False(表示终端用户看不到复选框或不能选择永久保存登录cookie),RememberMeSet属性设置为True,就自动在用户的机器上设置一个cookie,而不需要用户知道或选择。采用这种方式时必须慎重,因为终端用户有时使用公共计算机,这种方式会把授权cookie放在公共机器上。

这个cookie会保留在客户机上,直到用户从应用程序中注销为止(若提供这个选项)。有了永久保存的cookie,并假定终端用户没有从应用程序中注销,该用户在返回应用程序时,将永远不需要再次登录,因为他的凭证由cookie中的内容提供。终端用户登录到应用程序中后,就会返回最初要访问的页面。

还可以修改Login控件的外观和操作方式,这与其他控件一样。一种方式是在控件的智能标记上单击Auto Format链接,打开一个选项列表,找出修改该控件外观和操作方式的选项,如图18-8所示。

图  18-8

例如,选择Elegant选项,修改代码。程序清单18-14显示了所生成的代码。

程序清单18-14  格式化的Login控件

<asp:Login ID="Login1" Runat="server" BorderWidth="1px" BorderColor="#CCCC99"

 BorderStyle="Solid" BackColor="#F7F7DE" Font-Names="Verdana" Font-Size="10pt">

   <TitleTextStyle Font-Bold="True" BackColor="#6B696B" 

    ForeColor="#FFFFFF"></TitleTextStyle>

</asp:Login>

在这个程序清单中,<InstructionTextStyle>和<TitleTextStyle>子元素用于修改控件显示的特定项。Login控件的样式元素如下:

●       <CheckboxStyle>

●       <FailureTextStyle>

●       <HyperLinkStyle>

●       <InstructionTextStyle>

●       <LabelStyle>

●       <LoginButtonStyle>

●       <TextBoxStyle>

●       <TitleTextStyle>

●       <ValidatorTextStyle>

Login控件的许多属性都可以修改控件的外观和操作方式。一个有趣的变化是可以在控件的底部添加一些链接,来访问其他资源。通过这些链接,可以给用户提供帮助,或注册到应用程序中,这样他们能提供登录凭证。

下面是可以提供的一些链接:

●       使用HelpPageText、HelpPageUrl和HelpPageIconUrl属性可以重定向到帮助页面上。

●       使用CreateUserText、CreateUserUrl和CreateUserIconUrl属性可以重定向到注册页面上。

●       使用PasswordRecoveryText、PasswordRecoveryUrl和PasswordRecoveryIconUrl属性可以重定向到一个页面上,该页面允许用户恢复其忘记的密码。

使用这些链接,Login控件如图18-9所示。

图  18-9

3. 编程登录用户

除了使用Login控件的预定义机制之外,还可以使用Membership类编程完成这个任务。为了验证接收到的凭证,可以使用这个类的ValidateUser方法。ValidateUser方法有一个签名:

Membership.ValidateUser(username As String, password As String)

这个方法如程序清单18-15中所示。

程序清单18-15  编程验证用户的凭证

VB

If Membership.ValidateUser(TextBox1.Text, TextBox2.Text) Then

   FormsAuthentication.RedirectFromLoginPage(TextBox1.Text, False)

Else

   Label1.Text = "You are not registered with the site."

End If

C#

if (Membership.ValidateUser(TextBox1.Text, TextBox2.Text) {

   FormsAuthentication.RedirectFromLoginPage(TextBox1.Text.ToString(), false);

}

else {

   Label1.Text = "You are not registered with the site.";

}

如果用户的凭证通过了测试,ValidateUser方法就返回布尔值True,否则就返回False。在程序清单18-14的代码中,其凭证通过验证的终端用户会使用RedirectFromLoginPage方法退出注册页面。这个方法的参数是用户名和布尔值,该布尔值指定凭证是否通过cookie设置来保存。

4. 锁定输入错误密码的用户

在我们建立的应用程序中为用户提供登录窗体时,一定要防止用户多次尝试输入错误的密码。如果怀有恶意的用户知道一个用户名,就会多次试用不同的密码来访问应用程序。一定要阻止这类行为,不能让这个人用该用户名尝试输入上百个可能的密码。

ASP.NET 2.0内置了这类行为的防御措施。在aspnet_Membership表中,有两列就用于防止这类行为:FailedPasswordAttemptCount和FailedPasswordAttemptWindowStart。

默认情况下,在一个显示10分钟的窗口中,给同一个用户名输入不正确的密码至多只能尝试5次。第5次尝试失败后,账户就会被锁定。因为这会在ASP.NET 2.0中将IsLockedOut列设置为true。

可以控制允许输入密码的次数和应用程序中登录窗口的显示时间长度。这两项在machine.config文件的SqlMembershipProvider声明中定义。可以在服务器的配置文件或应用程序的web.config文件中修改它们的值。在web.config文件中修改它们的过程如程序清单18-16所示。

程序清单18-16  在提供程序声明中修改密码尝试次数

<configuration>

<system.web>

<membership defaultProvider="AspNetSqlMembershipProvider">

<providers>

<clear />

<add connectionStringName="LocalSqlServer"

applicationName="/"

maxInvalidPasswordAttempts="3"

passwordAttemptWindow="15"

name="AspNetSqlMembershipProvider"

type="System.Web.Security.SqlMembershipProvider, System.Web,

Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

</providers>

</membership>

</system.web>

</configuration>

要确定允许的密码尝试次数,可以使用maxInvalidPasswordAttempts属性。本例把这个值改为3,表示在账户被锁定之前,用户可以(在窗口指定的时间内)输入3次不正确的密码。maxInvalidPasswordAttempts属性的默认值是5。允许输入错误密码的窗口的显示时间使用passwordAttemptWinodw属性设置为15分钟。这个属性的默认值是10,所以本例增加了5分钟。

有了这些项后,下一步就是测试它。程序清单18-17是一个测试示例,它假定已建立了一个应用程序,添加了一个用户。

程序清单18-17  测试密码输入次数的示例页面

VB

<%@ Page Language="VB" %>

<script runat="server">

Protected Sub Button1_Click(ByVal sender As Object, _

ByVal e As System.EventArgs)

If CheckBox1.Checked = True Then

Dim user As MembershipUser = Membership.GetUser(TextBox1.Text)

user.UnlockUser()

End If

If Membership.ValidateUser(TextBox1.Text, TextBox2.Text) Then

Label1.Text = "You are logged on! "

Else

Dim user As MembershipUser = Membership.GetUser(TextBox1.Text)

Label1.Text = "Locked out value: " & user.IsLockedOut.ToString()

End If

End Sub

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Login Page</title>

</head>

<body>

<form id= "form1" runat="server">

<div>

<h1>Login User</h1>

<p>

<asp:CheckBox ID="CheckBox1" runat="server" Text="Unlock User" />

</p>

<p>

Username<br />

<asp:TextBox ID="TextBox1" Runat="server"></asp:TextBox>

</p>

<p>Password<br />

<asp:TextBox ID="TextBox2" Runat="server"

TextMode="Password"></asp:TextBox>

</p>

<p>

<asp:Button ID="Button1" Runat="server" Text="Login"

OnClick="Button1_Click" />

</p>

<p>

<asp:Label ID="Label1" Runat="server"></asp:Label>

</p>

</div>

</form>

</body>

</html>

C#

<%@ Page Language="C#" %>

<script runat="server">

protected void Button1_Click(object sender, EventArgs e)

{

if (CheckBox1.Checked == true)

{

MembershipUser user = Membership.GetUser(TextBox1.Text);

user.UnlockUser();

}

if (Membership.ValidateUser(TextBox1.Text, TextBox2.Text))

{

Label1.Text = "You are logged on! ";

}

else

{

MembershipUser user = Membership.GetUser(TextBox1.Text);

Label1.Text = "Locked out value: " + user.IsLockedOut.ToString();

}

}

</script>

这个页面包含两个文本框,分别用于输入用户名和密码。除了这些文本框之外,还有一个复选框,在账户因输入了错误的密码而被锁定后,可以使用该复选框解除锁定。

运行这个页面,给用户输入3次不正确的密码,就会得到如图18-10所示的结果。

图  18-10

IsLockOut属性通过MembershipUser对象的实例来读取。这个对象允许编程访问包含在aspnet_Membership表中的用户数据。本例获取IsLockOut属性后,把它显示在屏幕上。MembershipUser对象也有许多方法,其中一个是UnlockUser()方法,如果在按钮单击事件中选择了复选框,就会调用这个方法。

18.3.4  处理验证用户

用户通过验证后,ASP.NET 2.0中许多不同的服务器控件和方法就可以用于处理用户信息了。在这个工具集合中,包含LoginStatus和LoginName控件。

1. LoginStatus服务器控件

LoginStatus服务器控件可以让用户单击链接,在站点上注册或注销。作为这个控件的一个示例,从web.config文件中删除<deny>元素,使站点的页面可以由未验证的用户访问。然后编写Default.aspx页面,代码如程序清单18-18所示。

程序清单18-18  LoginStatus控件的登录和注销功能

<%@ Page Language="VB" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Login or Logout</title>

</head>

<body>

    <form id="form1" runat="server">

        <asp:LoginStatus ID="LoginStatus1" Runat="server" />

    </form>

</body>

</html>

运行这段代码,会显示一个简单的页面,其中只包含一个超链接Login,如图18-11所示。

图  18-11

单击Login超链接会进入Login.aspx页面,在这里提供凭证。提供了凭证后,就会重定向到Default.aspx页面,但现在页面包含超链接Logout,如图18-12所示。用户未通过验证时,LinkStatus控件显示一个链接,通过验证后显示另一个链接。单击Logout超链接,会注销用户,重新绘制Default.aspx页面,但这次会显示超链接Login。

2. LoginName服务器控件

LoginName服务器控件可以显示验证用户的用户名。这是一个很常见的方法。作为该控件的一个示例,修改Default.aspx页面,使之在用户登录时包含验证用户的登录名,如程序清单18-19所示。

图  18-12

程序清单18-19  显示验证用户的用户名

<%@ Page Language="VB" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Login or Logout</title>

</head>

<body>

    <form id="form1" runat="server">

        <asp:LoginStatus ID="LoginStatus1" Runat="server" />

        <p><asp:LoginName ID="LoginName1" Runat="server"

            Font-Bold="True" Font-Size="XX-Large" /></p>

    </form>

</body>

</html>

用户登录到应用程序上,并返回到Default.aspx页面时,会显示他的用户名和LoginStatus控件生成的超链接,如图18-13所示。

图  18-13

除了显示登录用户的用户名之外,还可以使用LoginName控件的FormatString属性添加文本。例如,要提供一个欢迎消息和用户名,可以按如下代码构建LoginName控件:

<asp:LoginName ID="LoginName1" Runat="Server"

 FormatString="Welcome to our Website {0}!" />

还可以在一个页面事件上使用如下构建代码(这是VB代码,如果使用C#,应在行末添加一个分号):

LoginName1.FormatString = "Welcome to the site {0}!"

在生成页面时,ASP.NET会用登录用户的用户名替换字符串的{0}部分。结果如下所示:

Welcome to the site evjen!

如果不想在使用LoginName控件时显示用户名,可以忽略字符串的{0}部分。控件会把FormatString属性的值放在页面上。

18.3.5  显示在线用户数

成员服务的一个特性是显示给定时刻在线的用户数。这是门户网站和论坛中非常常见的选项,以此向站点的访问者说明它的受欢迎程度。

为了显示在线用户数,可以使用Membership类的GetNumberOfUsersOnline方法。用程序清单18-20中的代码在图18-10所示的Default.aspx页面上添加这个功能。

程序清单18-20  显示在线用户数

VB

<%@ Page Language="VB" %>

<script runat="server">

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)

        Label1.Text = Membership.GetNumberOfUsersOnline().ToString()

    End Sub

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Login or Logout</title>

</head>

<body>

    <form id="form1" runat="server">

        <asp:LoginStatus ID="LoginStatus1" Runat="server" />

        <p><asp:LoginName ID="LoginName1" Runat="server"

            Font-Bold="True" Font-Size="XX-Large" /></p>

        <p>There are <asp:Label ID="Label1" Runat="server" Text="0" />

           users online.</p>

    </form>

</body>

</html>

C#

<%@ Page Language="C#" %>

<script runat="server">

   protected void Page_Load(object sender, EventArgs e)

   {

      Label1.Text = Membership.GetNumberOfUsersOnline().ToString();

   }

</script>

生成页面时,会显示过去15分钟内登录的用户数,结果如图18-14所示。

图  18-14

可以看出,过去15分钟内有两个用户登录。这个15分钟的时间在machine.config文件的<membership>元素中确定:

<membership userIsOnlineTimeWindow="15" >

</membership>

userIsOnlineTimeWindow默认设置为15。这里指定的数字以分钟为单位。要增加这个时间,可以增大这个值。除了在machine.config文件中指定这个数字之外,还可以在web.config文件中设置这个数字。

18.3.6  处理密码

我们上网时,常常在Internet的许多不同的Web站点上使用用户名和密码组合。所以,终端用户常常会忘记密码或要改变密码。ASP.NET 2.0提供了两个新服务器控件来使用成员服务,让终端用户可以修改密码,或找回忘记的密码。

1. ChangePassword服务器控件

ChangePassword服务器控件允许终端用户直接在浏览器上修改密码。程序清单18-21显示了ChangePassword控件的用法。

程序清单18-21  允许用户修改密码

<%@ Page Language="VB" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Change Your Password</title>

</head>

<body>

    <form id="form1" runat="server">

        <asp:LoginStatus ID="LoginStatus1" Runat="server" />

        <p><asp:ChangePassword ID="ChangePassword1" Runat="server">

           </asp:ChangePassword><p>

    </form>

</body>

</html>

这是<asp:ChangePassword>控件一个相当简单的用法。运行这个页面,结果如图18-15所示。

图  18-15

ChangePassword控件会生成一个窗体,要求用户输入以前的密码。它还需要终端用户输入两次新密码。如果用户已登录,单击Change Password按钮就会修改密码。如果终端用户没有登录到应用程序上,他就会被重定向到登录页面上,只有登录用户才能修改密码。修改密码后,会通知终端用户,如图18-16所示。

图  18-16

终端用户可以修改密码,因为成员提供程序的enablePasswordReset属性设置为True。为了关闭这个功能,可以把enablePasswordReset属性设置为False。

在终端用户修改密码时,还可以指定构建密码必须遵循的规则。例如,要求密码包含若干个字符,或者使用数字、特定的字符和alpha字符。使用NewPasswordRegularExpression属性可以指定新密码需要的构建规则,如下所示:

NewPasswordRegularExpression='@\"(?=.{6,})(?=(.*\d){1,})(?=(.*\W){1,})'

终端用户创建的新密码要利用这个正则表达式来检查。如果不匹配,就可以使用NewPasswordRegularExpressionErrorMessage属性(ASP.NET中一个名称很长的属性)在控件输出中显示一个错误消息。

2. PasswordRecovery 服务器控件

人们常常忘记密码。因此,应提供从数据库中提取密码的方式。PasswordRecovery服务器控件为此提供了一种简单的方式。

密码恢复通常通过电子邮件给终端用户发送密码。因此,需要建立一个SMTP服务器(它可能与应用程序服务器相同)。在web.config文件中配置这个服务器,如程序清单18-22所示。

程序清单18-22  在web.config文件中配置通过电子邮件传送的密码

<configuration>

   <system.web>

      <!-- Removed for clarity -->

   </system.web>

   <system.net>

  

      <mailSettings>

         <smtp from="evjen@yahoo.com">

            <network host="localhost" port="25"

             defaultCredentials="true" />

         </smtp>

      </mailSettings>

   </system.net>

</configuration>

正确建立了<mailSettings>元素后,就可以开始使用PasswordRecovery控件了。PasswordRecovery控件的简单用法如程序清单18-23所示。

程序清单18-23  使用PasswordRecovery控件

<%@ Page Language="VB" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Getting Your Password</title>

</head>

<body>

    <form id="form1" runat="server">

        <asp:PasswordRecovery ID="PasswordRecovery1" Runat="server">

            <MailDefinition From="evjen@yahoo.com">

            </MailDefinition>

        </asp:PasswordRecovery>

    </form>

</body>

</html>

<asp:PasswordRecovery>元素需要<MailDefinition>子元素。<MailDefinition>元素包含要发送给终端用户的电子邮件信息。最低要求是使用From属性,它提供了电子邮件中From部分的电子邮件地址。这个属性的String值应是一个电子邮件地址。<MailDefinition>元素的其他属性包括:

●       BodyFileName

●       CC

●       From

●       IsBodyHtml

●       Priority

●       Subject

运行这个页面,PasswordRecovery控件会要求输入用户的用户名,如图18-17所示。

图  18-17

有了用户名,成员服务就提取终端用户以前输入的问题和答案,并生成如图18-18所示的视图。

如果问题回答正确,就生成一个包含密码的电子邮件,并发送给终端用户。如果问题回答不正确,就显示一个错误消息。当然,如果禁用成员系统中的Question/Answer特性,就不使用问题。

要使整个过程起作用,改变一些成员服务设置是很重要的。目前该过程因为用户密码的散列方式还不能起作用。成员服务数据库没有存储实际的密码,只存储了密码的散列版本。当然,终端用户得到散列密码是没有用的。

图  18-18

为了能把实际密码发送回用户,必须修改密码在成员服务数据库中的存储方式。这可以通过改变成员数据提供程序的PasswordFormat属性(如本章前面所述)来完成。除了Hashed之外,它的另外两个值是Clear和Encrypted。把它改为Clear或Encrypted,密码就可以以可读的方式发送回终端用户。

3. 生成随机密码

一些应用程序在创建用户时,必须生成随机密码。在以前的ASP.NET 1.0/1.1中,这需要编写代码,而ASP.NET 2.0中有一个帮助方法,利用该方法可以获取随机密码。程序清单18-24就创建了一个帮助方法,以获得随机密码。

程序清单18-24  生成随机密码

VB

Protected Function GeneratePassword() As String

  Dim returnPassword As String

returnPassword = Membership.GeneratePassword(10, 3)

Return returnPassword

End Function

C#

Protected string GeneratePassword()

{

  string returnPassword;

returnPassword = Membership.GeneratePassword(10, 3);

                       

Return returnPassword;

}

要在ASP.NET 2.0中生成随机密码,可以使用GeneratePassword()帮助方法。这个方法可以生成指定长度的随机密码,还可以指定密码应至少包含多少个非数字字母的字符。这个例子使用了该方法5次,生成了如下结果(当然,读者的运行结果应与此不同):

●       D](KQg6s2[

●       $X.M9]*x2-

●       Q+lIy2#zD%

●       %kWZL@zy&f

●       o]&IhL#iU1

有了帮助方法后,就可以用随机密码创建用户了,如程序清单18-25所示。

程序清单18-25  用随机密码创建用户

VB

Membership.CreateUser(TextBox1.Text, GeneratePassword().ToString())

C#

Membership.CreateUser(TextBox1.Text, GeneratePassword().ToString());

posted on 2008-01-04 11:26  Eric Yao  阅读(504)  评论(0)    收藏  举报