本章内容
q Login控件概览
q 使用Login控件
q 使用CreateUserWizard控件
q 使用LoginStatus控件
q 使用LoginName控件
q 使用ChangePassword控件
q 使用PasswordRecovery控件
q 使用LoginView控件
q 小结
使用ASP.NET Login控件可以轻易创建网站的用户注册系统,Login控件能用于显示用户注册表单、用户登陆表单、修改密码表单和密码提示表单。
默认情况下,Login控件使用ASP.NET提供的Membership来认证用户、创建新用户以及修改用户属性。在使用Login控件时,完成这些任务不需要编写任何代码。
注解 本书下一章将对ASP.NET Membership进行详细讨论。
本章第一部分将对Login控件作概览性的介绍,学习如何使用密码认证来保护网站的内容,以及如何让用户注册和登陆网站。
本章其余部分将详细介绍如何使用Login控件提供的下列属性:
q Login——用于显示用户登录表单;
q CreateUserWizard——用于显示用户注册表单;
q LoginStatus——用于显示登录或登出链接,该链接类型依赖于当前用户的认证状态;
q LoginName——用于显示当前注册用户的用户名;
q ChangePassword——用于显示修改用户密码的表单;
q PasswordRecovery——用于显示找回用户密码的表单;
q LoginView——用于根据用户认证状态或角色为不同的用户显示自定义内容。
1.1 Login控件概览
除非有机密信息需要保护,否则使用Login控件并不是一件轻松有趣的事。因此,让我们从创建一个需要使用密码进行保护的页面来开始本章的学习。
在应用程序中创建一个名为SecretFiles的文件夹,并将代码清单1-1中的页面放入该文件夹中。
代码清单1-1 SecretFiles/Secret.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Secret</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>This Page is Secret!</h1>
</div>
</form>
</body>
</html>
代码清单1-1中的页面没有什么特殊之处,它只是会显示信息This Page is Secret!(这个页面是保密的)。
如果希望通过密码认证来保护页面Secret.aspx,那么就需要对应用程序做两个配置更改:配置认证和授权设置。
首先,要为应用程序开启适当的认证类型。系统在默认情况下会启用Windows认证。但是只有在应用程序根目录下加入代码清单1-2中的Web配置文件,以启用Forms认证后,才能使用Login控件。
代码清单1-2 Web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<authentication mode="Forms" />
</system.web>
</configuration>
代码清单1-2中的Web配置文件包含了一个认证节点,该节点有一个mode属性,并且该mode属性的值为Forms。
注解 认证和授权的内容将在本书第2章详细讨论。
在默认情况下,任何用户都可以访问应用程序中的所有页面。如果要在某个文件夹中对访问进行限制,那么就必须配置该文件夹的认证设置。
如果将代码清单1-3中的Web配置文件加入到SecretFiles文件夹中,那么匿名用户就不能再访问该文件夹中的任何页面。
代码清单1-3 SecretFiles/Web.Config
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
代码清单1-3中的Web配置文件包含了一个授权节点。该节点中包含了一个控制该目录授权角色的列表。代码清单1-3中的单一授权角色将阻止匿名用户访问该文件夹(其属性值?表示匿名用户)。
|
Visual Web 如果你愿意,还可以使用Web站点管理工具来配置认证和授权设置。该工具提供一个表单界面来执行对应用程序配置的修改。使用Visual Web Developer时,可以通过选取菜单选项:Website(网站)→ASP.NET Configuration(ASP.NET配置)来打开Web 站点管理工具。
当代码清单1-3中的Web配置文件添加到SecretFiles目录中后,如果这时去尝试访问页面Secret.aspx,那么用户请求将会自动地重定向到一个名为Login.aspx的页面上。因此,接下来需要创建的页面就是Login.aspx(在默认情况下,必须将该页面放置在应用程序的根目录中)。
代码清单1-4的Login.aspx页面中包含了一个Login控件,该控件将自动生成一个用户登录表单(见图1-1)。
图1-1 显示登录表单
代码清单1-4 Login.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Login</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Login
id="Login1"
CreateUserText="Register"
CreateUserUrl="~/Register.aspx"
Runat="server" />
</div>
</form>
</body>
</html>
需要注意的是,Login控件包含了一个CreateUserText和一个CreateUserUrl属性。添加这些属性后,Login控件就会显示一个为该应用程序注册新用户的链接。代码清单1-4中Login控件的新建用户链接指向了一个名为Register.aspx的页面,而该页面的定义包含在代码清单1-5中。
代码清单1-5 Register.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Register</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
ContinueDestinationPageUrl="~/SecretFiles/Secret.aspx"
Runat="server" />
</div>
</form>
</body>
</html>
该页面中包含了一个CreateUserWizard控件,该控件会自动创建用户注册表单(见图1-2)。当用户提交了该表单后,应用程序将创建一个新用户,并将用户请求重定向回页面Secret.aspx。
图1-2 显示用户注册表单
注意 默认的ASP.NET Membership接口提供器需要创建一个至少7位的密码,并且密码中还必须要有非数字和文字的字符。因此,secrte_是一个有效的密码,但是secret9却不是。在下一章中,我们将详细介绍如何修改这个默认的密码复杂度要求。
到此为止,需要注意的是,在没有编写一行代码的情况下,我们就已经完成了一个简单的用户注册系统。至于那些存储用户名和密码的所有杂乱细节,都在后台通过ASP.NET Framework自动进行处理。
.2 使用Login控件
Login控件将用于输出标准的用户登录表单。在默认请况下,该控件使用ASP.NET Membership来认证用户。然而,正如我们在刚才的示例中所看到的那样,还可以通过自定义Login控件来对用户进行认证。
Login控件支持大量的属性,使用这些属性可以定制控件的外观和行为(由于属性实在太多,因此不再一一列出)。代码清单1-6中的页面例举了如何通过修改Login控件的属性来定制控件的输出(见图1-3)。
代码清单1-6中的页面使用CSS来修改Login控件输出的登录表单的外观。通过利用CSS,可以根据需要自定义Login控件的外观。
注解 Login控件所支持的完整属性列表,可以参看微软.NET Framework SDK 2.0文档。
图1-3 自定义Login表单
代码清单1-6 ShowLogin.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Show Login</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Login
id="Login1"
InstructionText="Please log in before
accessing the premium section of our Website."
TitleText="Log In"
TextLayout="TextOnTop"
LoginButtonText="Log In"
DisplayRememberMe="false"
CssClass="login"
TitleTextStyle-CssClass="login_title"
InstructionTextStyle-CssClass="login_instructions"
LoginButtonStyle-CssClass="login_button"
Runat="server" />
</div>
</form>
</body>
</html>
1.2.1 用户自动重定向来源页面
如果用户访问了一个未经授权的页面,那么ASP.NET Framework将会自动把页面重定向到Login.aspx页面。当用户登录成功后,会再次重定向到用户起初访问的那个页面上。
重定向到Login.aspx页面后,一个名为ReturnUrl的查询字符串(query string)参数会被自动添加到该页面的请求路径上。Login控件在需重定向回用户来源页面时,会使用该参数进行返回定位。
需要了解两种特殊情况。首先,如果用户直接访问Login.aspx页面,那么将没有ReturnUrl参数值传递给Login.aspx页面。这样一来,用户成功登录后,访问就会被重定向到默认页面Default.aspx上。
第二种情况,如果将Login控件添加到了Login.aspx以外的页面,那么ReturnUrl这个查询字符串参数就会被系统忽略。这样一来,就需要设置Login控件的DestinationPageUrl属性。这样当用户成功登录后,该访问将会被重定向到DestinationPageUrl属性所指定的URL上。如果不设置DestinationPageUrl属性,那么该页面本身会被重新载入。
1.2.2 自动隐藏已认证用户的Login控件
有一些网站会在每个页面的顶部显示其登录表单。如此一来,其注册用户可以在任意时刻登录网站以浏览更多的内容。将Login控件添加到应用程序所有页面中的最简单方法是利用母版页。如果将Login控件加入到母版页中,那么使用该母版页的所有内容页面中都会包含该Login控件。
通过Login控件的Orientation属性,可以改变该控件的布局效果。如果将该属性值设置为Horizontal,那么用户名(Username)和密码(Password)输入框就会被输出到同一行中。
如果应用程序的所有页面都包含了Login控件,那么我们还应该修改Login控件的Visible- WhenLoggedIn属性。如果该属性被设置为false,那么用户认证成功后就不会再显示该Login控件。
例如,代码清单1-7中的母版页包含了一个Login控件,该控件使用了其属性集合中的Orientation和VisibleWhenLoggedIn两个属性。
代码清单1-7 LoginMaster.master
<%@ Master Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>My Website</title>
</head>
<body>
<form id="form1" runat="server">
<div class="content">
<asp:Login
id="Login1"
Orientation="Horizontal"
VisibleWhenLoggedIn="false"
DisplayRememberMe="false"
TitleText=""
CssClass="login"
Runat="server" />
<hr />
<asp:contentplaceholder
id="ContentPlaceHolder1"
runat="server">
</asp:contentplaceholder>
</div>
</form>
</body>
</html>
代码清单1-8中的页面使用了代码清单1-7中的母版页(见图1-4)。当使用浏览器访问该页面时,用户一旦成功登录到该应用程序中,其Login控件就会自动隐藏起来。
图1-4 将Login控件放入母版页中
代码清单1-8 LoginContent.aspx
<%@ Page Language="C#" MasterPageFile="~/LoginMaster.master" %>
<asp:Content
ID="Content1"
ContentPlaceHolderID="ContentPlaceHolder1"
Runat="Server">
<h1>Welcome to our Website!</h1>
</asp:Content>
1.2.3 使用模板定制Login控件
我们可以使用模板来完整地定制Login控件的外观。通过设置Login控件提供的LayoutTemplate属性,可以方便地自定义该控件的输出布局。
在创建布局模板时,可以将包含下列特定ID值的控件添加到模板中:
q UserName
q Password
q RememberMe
q FailureText
同时也还需要添加CommandName属性值为Login的Button控件。
代码清单1-9中的页面展示了如何使用LayoutTemplate来自定义Login控件的外观(见图1-5)。
图1-5 使用模板来定制Login控件
代码清单1-9 LoginTemplate.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<style type="text/css">
.loginError
{
color:red;
font:bold 14px Arial,Sans-Serif;
}
</style>
<title>Login Template</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Login
id="Login1"
Runat="server">
<LayoutTemplate>
<asp:Label
id="FailureText"
EnableViewState="false"
CssClass="loginError"
Runat="server" />
<br />
<asp:Label
id="lblUserName"
AssociatedControlID="UserName"
Text="Username:"
Runat="server" />
<br />
<asp:TextBox
id="UserName"
Runat="server" />
<br /><br />
<asp:Label
id="lblPassword"
AssociatedControlID="Password"
Text="Password:"
Runat="server" />
<br />
<asp:TextBox
id="Password"
TextMode="Password"
Runat="server" />
<br /><br />
<asp:Button
id="btnLogin"
Text="Login"
CommandName="Login"
Runat="server" />
</LayoutTemplate>
</asp:Login>
</div>
</form>
</body>
</html>
|
Web标 用LayoutTemplate属性来自定义Login控件后,该控件将通过输出一个HTML表格来进行布局。
1.2.4 使用Login控件执行自定义认证
默认情况下,Login控件使用ASP.NET Membership来认证用户名和密码。如果要修改此默认行为,那么可以对Login控件的Authenticate事件进行处理。
例如,假设你在创建一个简单的应用程序,并且需要将用户名和密码列表存放在Web配置文件中。代码清单1-10中的Web配置文件包含了Bill和Ted两个用户的信任凭证。
代码清单1-10 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<authentication mode="Forms">
<forms>
<credentials passwordFormat="Clear">
<user name="Bill" password="secret" />
<user name="Ted" password="secret" />
</credentials>
</forms>
</authentication>
</system.web>
</configuration>
代码清单1-11中的页面包含了一个Login控件,该控件依靠存储在Web配置文件中的用户名和密码来对用户进行认证。
代码清单1-11 LoginCustom.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
string userName = Login1.UserName;
string password = Login1.Password;
e.Authenticated = FormsAuthentication.Authenticate(userName, password);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Login Custom</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Login
id="Login1"
OnAuthenticate="Login1_Authenticate"
Runat="server" />
</div>
</form>
</body>
</html>
需要注意的是,代码清单1-11中的页面包含了一个处理Login控件Authenticate事件的事件处理函数。传递给该Authenticate事件处理函数的第二个参数是一个AuthenticateEventArgs类的实例。该类中包含下列属性:
q Authenticated
如果该属性设置为true,那么Login控件就会通过对该用户的认证。
在代码清单1-11中,调用FormsAuthentication.Authenticate()方法,将会检查Web配置文件中的用户名和密码是否与登录表单中输入的用户名和密码相匹配。这个方法的返回值将会被赋给AuthenticateEventArgs.Authenticated属性。
1.3 使用CreateUserWizard控件
CreateUserWizard控件会输出一个用户注册表单。如果用户成功提交了该表单,那么一个新用户将添加到网站中。在后台,CreateUserWizard控件使用ASP.NET Membership来创建新用户。
CreateUserWizard控件支持大量的属性(由于属性实在太多,因此不再一一列举),通过这些属性我们可以修改该控件的外观和行为。例如,代码清单1-12中的页面使用了CreateUserWizard控件的几个属性来自定义控件的外观输出。
代码清单1-12 ShowCreateUserWizard.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<style type="text/css">
.createUser
{
width:350px;
font:14px Verdana,Sans-Serif;
background-color:lightblue;
border:solid 3px black;
padding:4px;
}
.createUser_title
{
background-color:darkblue;
color:white;
font-weight:bold;
}
.createUser_instructions
{
font-size:12px;
text-align:left;
padding:10px;
}
.createUser_button
{
border:solid 1px black;
padding:3px;
}
</style>
<title>Show CreateUserWizard</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
ContinueDestinationPageUrl="~/Default.aspx"
InstructionText="Please complete the following form
to register at this Website."
CompleteSuccessText="Your new account has been
created. Thank you for registering."
CssClass="createUser"
TitleTextStyle-CssClass="createUser_title"
InstructionTextStyle-CssClass="createUser_instructions"
CreateUserButtonStyle-CssClass="createUser_button"
ContinueButtonStyle-CssClass="createUser_button"
Runat="server" />
</div>
</form>
</body>
</html>
代码清单1-12中的CreateUserWizard控件通过CSS进行了定制(见图1-6)。需要注意的是,该控件的ContinueDestinationPageUrl属性被设置为了"~/Default.aspx"。当用户注册成功后,将会被重定向到该Default.aspx页面。
图1-6 定制CreateUserWizard控件
注解 我们可以通过微软.NET Framework SDK 2.0 文档来了解CreateUserWizard控件所支持的完整属性列表。
1.3.1 配置自定义用户表单字段
在默认情况下,CreateUserWizard控件将会显示下列表单字段:
q Username
q Password
q Confirm Password
q Email
q Security Question
q Security Answer
以上是默认提供的表单项,最后三项是可选的。
如果不需要用户输入电子邮件地址或安全问题提示及答案,那么就需要修改默认的Membership接口提供器。代码清单1-13中的Web配置文件,配置了CreateUserWizard控件是否需要电子邮件地址和安全问题提示及答案表单项。
代码清单1-13 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<authentication mode="Forms" />
<membership defaultProvider="MyMembership">
<providers>
<add
name="MyMembership"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="LocalSqlServer"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="false" />
</providers>
</membership>
</system.web>
</configuration>
如果将代码清单1-13中的Web配置文件加入应用程序中,那么CreateUserWizard控件将不会输出安全问题提示及答案表单项。但其仍会输出一个电子邮件表单项。如果连电子邮件地址表单项也不需要输出,那么还需要做一些额外的操作。必须将CreateUserWizard控件的RequireEmail属性设置为false。
如果将代码清单1-14中的页面加入使用代码清单1-13中Web配置文件的应用程序中,那么电子邮件地址、安全问题提示和安全问题答案表单项就都不会显示(见图1-7)。
图1-7 精简版的用户注册表单
代码清单1-14 CreateUserWizardShort.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>CreateUserWizard Short</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
RequireEmail="false"
Runat="server" />
</div>
</form>
</body>
</html>
注意 当Membership接口提供器的requireUniqueEmail属性被设为true值时,请不要将CreateUserWizard控件的RequireEmail属性设为false值。换句话说,就是在不给用户提供电子邮件地址输入表单项时,不要让用户提供电子邮件地址。
1.3.2 发送已创建用户电子邮件通知
可以通过配置CreateUserWizard控件,使其在注册新用户后自动地发送电子邮件通知。例如,可以向该用户电子邮件地址发送一封包含了新注册用户的用户名和密码的通知邮件。
注意 通过互联网来发送包含用户密码的未加密电子邮件是非常危险的。然而,这样发送包含密码的注册确认邮件也是目前很普遍的行为。
代码清单1-15中的页面包含MailDefinition属性,该属性用来表示当用户成功注册后,向该用户发送的确认电子邮件的定义。
代码清单1-15 CreateUserWizardEmail.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>CreateUserWizard Email</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
Runat="server">
<MailDefinition
BodyFileName="Register.txt"
Subject="Registration Confirmation"
From="Admin@YourSite.com" />
</asp:CreateUserWizard>
</div>
</form>
</body>
</html>
该MailDefinition类支持下列属性:
q BodyFileName——用于指定电子邮件通知正文内容的文件路径;
q CC——用于表示抄送该电子邮件的邮件地址;
q EmbeddedObjects——用于在电子邮件中嵌入对象,例如图片、文档等;
q From——用于指定电子邮件的来源邮件地址;
q IsBodyHtml——用于指示是否发送HTML格式的电子邮件;
q Priority——用于指定电子邮件的发送优先级。可能取值为Hight、Low和Normal;
q Subject——用于指定电子邮件的标题。
在代码清单1-15中,关联到CreateUserWizard控件上的MailDefinition类将会通过电子邮件发送代码清单1-16中的文本文件内容。
代码清单1-16 Register.txt
Thank you for registering!
Here is your new username and password:
username: <% UserName %>
password: <% Password %>
这里需要注意的是,代码清单1-16中的电子邮件通知正文中包含了两个特殊的表达式:<% UserName %>和<% Password %>。当发送电子邮件时,系统会自动地将用户的注册用户名和密码替换到该表达式中(见图1-8)。
图1-8 收到的注册电子邮件通知
注解 我们也可以在电子邮件通知中,发送通过Membership提供器进行加密或散列过的用户密码。
MailDefinition类使用Web配置文件中smtp节点的定义来配置电子邮件服务器端。例如,在代码清单1-17 的Web配置文件中,示例了如何在互联网信息服务器端(IIS)上配置本地SMTP邮件服务器端,以供MailDefinition类发送电子邮件使用(我们可以从管理工具文件夹中打开IIS管理器,启用本地SMTP服务)。
代码清单1-17 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.net>
<mailSettings>
<smtp deliveryMethod="PickupDirectoryFromIis"/>
</mailSettings>
</system.net>
<system.web>
<authentication mode="Forms" />
</system.web>
</configuration>
如果要连接位于另一台服务器端上的电子邮件服务器端,可以使用代码清单1-18中的Web配置文件。代码清单1-18中,节点smtp的定义中包含了一个用于指定电子邮件主机地址、用户名和密码的network节点。
代码清单1-18 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.net>
<mailSettings>
<smtp>
<network
host="mail.YourServer.com"
userName="admin"
password="secret" />
</smtp>
</mailSettings>
</system.net>
<system.web>
<authentication mode="Forms" />
</system.web>
</configuration>
注解 如果要自定义CreateUserWizard控件发送的电子邮件通知的内容,那么我们可以处理CreateUserWizard控件提供的事件SendingMail。详细信息见 1.3.3 节中的页面CreateUserWizard- CodeConfirmation.aspx。
1.3.3 用户自动重定向来源页面
当用户通过页面Login.aspx中的表单成功登录后,将会自动地重定向回其请求的来源页面。另外,CreateUserWizard控件并不能自动地重定向到任何位置。如果你希望CreateUserWizard控件能像Login控件那样工作,则需要编写一定的代码。
代码清单1-19中的Login控件包含了一个用于连接到用户注册页面CreateUserWizard- Returen.aspx上的链接。在Page_Load()事件处理函数中,查询字符串参数ReturnUrl将被添加到该注册页面的链接上。
代码清单1-19 LoginReturn.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string dest = Request.QueryString["ReturnUrl"];
Login1.CreateUserUrl = "~/CreateUserWizardReturn.aspx?ReturnUrl=" + Server.UrlEncode(dest);
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Login Return</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Login
id="Login1"
CreateUserText="Register"
CreateUserUrl="~/CreateUserWizardReturn.aspx"
Runat="server" />
</div>
</form>
</body>
</html>
在使用代码清单1-19中的页面之前,需要将该页面重命名为Login.aspx。如果未认证用户访问了需要认证才能访问的页面,那么该用户访问请求就会被自动重定向到页面Login.aspx上,并且ReturnUrl参数也会自动添加到页面Login.aspx的访问路径之后。
代码清单1-20中的页面包含了一个CreateUserWizard控件,以及一个名为Page_Load()的事件处理函数。查询字符串参数ReturnUrl的值用来指定重定向时用户将会返回的原始请求页。
代码清单1-20 CreateUserWizardReturn.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
void Page_Load()
{
if (!Page.IsPostBack)
{
string dest = "~/Default.aspx";
if (!String.IsNullOrEmpty(Request.QueryString["ReturnURL"]))
dest = Request.QueryString["ReturnURL"];
CreateUserWizard1.ContinueDestinationPageUrl = dest;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>CreateUserWizard Return</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
Runat="server" />
</div>
</form>
</body>
</html>
1.3.4 自动生成密码
有一部分网站在进行注册时候需要多个步骤。例如,要在eBay上注册一个新账号就必须要完成下列步骤:
(1) 仔细填写完成用户注册表单;
(2) 接收包含注册认证码的电子邮件;
(3) 将认证码填入指定表单中进行确认。
使用这样的注册方式可以检验用户输入的电子邮件地址是否有效。如果是无效的电子邮件地址,他就不能接收到注册认证码。
要实现这样的注册方案,就必须了解CreateUserWizard控件的下列三个属性:
q AutoGeneratePassword——用于指定控件是否自动产生新密码;
q DisableCreatedUser——用于禁止通过控件创建新用户账号;
q LoginCreateUser——用于在自动登录中保护新用户。
同时还可以发送两种类型的注册确认电子邮件通知。其一,可以自动生成新密码并将该密码发送给进行注册的用户。这种方式需要启用控件的AutoGeneratePassword属性,同时禁用其LoginCreateUser属性。
另外一种是让用户自己输入密码,然后在电子邮件的确认通知中发送特别的认证码。而这需要启用控件的DisableCreatedUser属性,并同时禁用LoginCreateUser属性。下面让我们分别对这些方案进行试验。
代码清单1-21中的页面包含了CreateUserWizard控件,但该控件并不输出密码表单项。该控件启用了AutoGeneratePassword属性,同时禁用了LoginCreateUser属性。在填写完成由CreateUserWizard控件输出的用户注册表单后,点击Continue按钮将会打开页面Login.aspx。
代码清单1-21 CreateUserWizardPasswordConfirmation.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>CreateUserWizard Password Confirmation</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
CompleteSuccessText="A confirmation email
containing your new password has been
sent to your email address."
AutoGeneratePassword="true"
LoginCreatedUser="false"
ContinueDestinationPageUrl="~/Login.aspx"
Runat="server">
<MailDefinition
From="Admin@YourSite.com"
BodyFileName="PasswordConfirmation.htm"
IsBodyHtml="true"
Subject="Registration Confirmation" />
</asp:CreateUserWizard>
</div>
</form>
</body>
</html>
注意 在启用了CreateUserWizard控件自动生成密码功能后,请不要再设置Membership接口提供器的passwordStrengthRegularExpression属性。
代码清单1-21中的CreateUserWizard控件发送的电子邮件通知将会包含代码清单1-22中的内容。
代码清单1-22 PasswordConfirmation.htm
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Password Confirmation</title>
</head>
<body>
Your new password is <% Password %>.
</body>
</html>
代码清单1-22中的电子邮件通知中包含了自动生成的密码。当新用户收到了自动生成的用户密码后,便可以在应用程序的Login.aspx页面中输入该密码进行登录。
在另一种使用场景中,用户可以自己选择密码。然而,该用户的账号在其输入注册验证码进行确认前是不能使用的。
代码清单1-23中的CreateUserWizard控件启用了其DisableCreateUser属性,并同时禁用了LoginCreateUser属性。
代码清单1-23 CreateUserWizardCodeConfirmation.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void CreateUserWizard1_SendingMail(object sender, MailMessageEventArgs e)
{
MembershipUser user = Membership.GetUser(CreateUserWizard1.UserName);
string code = user.ProviderUserKey.ToString();
e.Message.Body = e.Message.Body.Replace("<%ConfirmationCode%>", code);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>CreateUserWizard Code Confirmation</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
CompleteSuccessText="A confirmation email
containing your new password has been
sent to your email address."
DisableCreatedUser="true"
ContinueDestinationPageUrl="~/ConfirmCode.aspx"
OnSendingMail="CreateUserWizard1_SendingMail"
Runat="server">
<MailDefinition
From="Admin@YourSite.com"
BodyFileName="CodeConfirmation.htm"
IsBodyHtml="true"
Subject="Registration Confirmation" />
</asp:CreateUserWizard>
</div>
</form>
</body>
</html>
需要注意的是,代码清单1-23中的页面包含了一个SendingMail事件处理函数。注册验证码是通过Membership接口提供器关联到每个新用户上的唯一键值(本示例中使用的是GUID)。该验证码在电子邮件通知发送前将输入到电子邮件中。该电子邮件通知的内容包含在代码清单1-24中。
代码清单1-24 CodeConfirmation.htm
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Code Confirmation</title>
</head>
<body>
<%UserName%>,
your confirmation code is <%ConfirmationCode%>
</body>
</html>
在填写完CreateUserWizard控件输出的表单后,便可以通过点击Continue按钮来打开页面ConfirmCode.aspx(见图1-9)。
图1-9 输入验证码
代码清单1-25 ConfirmCode.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void btnConfirm_Click(object sender, EventArgs e)
{
MembershipUser user = Membership.GetUser(txtUserName.Text);
if (user == null)
{
lblError.Text = "Invalid User Name";
}
else
{
string providerCode = user.ProviderUserKey.ToString();
string userCode = txtConfirmationCode.Text.Trim();
if (providerCode != userCode)
{
lblError.Text = "Invalid Confirmation Code";
}
else
{
user.IsApproved = true;
Membership.UpdateUser(user);
Response.Redirect("~/SecretFiles/Secret.aspx");
}
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Confirm Code</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p>
Enter the confirmation code that you received by email.
</p>
<asp:Label
id="lblError"
EnableViewState="false"
ForeColor="Red"
Runat="server" />
<br /><br />
<asp:Label
id="lblUserName"
Text="User Name:"
AssociatedControlID="txtUserName"
Runat="server" />
<br />
<asp:TextBox
id="txtUserName"
Runat="server" />
<br /><br />
<asp:Label
id="lblConfirmationCode"
Text="Confirmation Code:"
AssociatedControlID="txtConfirmationCode"
Runat="server" />
<br />
<asp:TextBox
id="txtConfirmationCode"
Columns="50"
Runat="server" />
<asp:Button
id="btnConfirm"
Text="Confirm"
OnClick="btnConfirm_Click"
Runat="server" />
</div>
</form>
</body>
</html>
当用户在特定的表单中输入了正确的用户名和相应的认证码后,其账号将正式启用。MembershipUser.IsApproved属性需要设置为true,然后再使用Membership.UpdateUser()方法来保存更新的用户信息。
1.3.5 在CreateUserWizard控件中使用模板
如果需要对CreateUserWizard控件输出表单的外观进行自定义,那么我们可以为CreateUserWizard和CompleteWizardStep控件创建模板。例如,在代码清单1-26 的页面中就使用了一个下拉列表框来显示安全提示问题的选项(见图1-10)。
图1-10 利用模板来自定义CreateUserWizard控件
代码清单1-26 CreateUserWizardTemplate.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>CreateUserWizard Template</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
Runat="server">
<WizardSteps>
<asp:CreateUserWizardStep>
<ContentTemplate>
<h1>Register</h1>
<asp:Label
id="ErrorMessage"
ForeColor="Red"
Runat="server" />
<br /><br />
<asp:Label
id="lblUserName"
Text="User Name:"
AssociatedControlID="UserName"
Runat="server" />
<br />
<asp:TextBox
id="UserName"
Runat="server" />
<br /><br />
<asp:Label
id="lblPassword"
Text="Password:"
AssociatedControlID="Password"
Runat="server" />
<br />
<asp:TextBox
id="Password"
TextMode="Password"
Runat="server" />
<br /><br />
<asp:Label
id="lblEmail"
Text="Email:"
AssociatedControlID="Email"
Runat="server" />
<br />
<asp:TextBox
id="Email"
Runat="server" />
<br /><br />
<asp:Label
id="lblQuestion"
Text="Security Question:"
AssociatedControlID="Question"
Runat="server" />
<br />
<asp:DropDownList
id="Question"
Runat="server">
<asp:ListItem
Text="Enter the name of your pet"
Value="Pet Name" />
<asp:ListItem
Text="Enter your favorite color"
Value="Favorite Color" />
</asp:DropDownList>
<br /><br />
<asp:Label
id="lblAnswer"
Text="Security Answer:"
AssociatedControlID="Answer"
Runat="server" />
<br />
<asp:TextBox
id="Answer"
Runat="server" />
</ContentTemplate>
</asp:CreateUserWizardStep>
<asp:CompleteWizardStep>
<ContentTemplate>
Your account was successfully created.
</ContentTemplate>
</asp:CompleteWizardStep>
</WizardSteps>
</asp:CreateUserWizard>
</div>
</form>
</body>
</html>
在CreateUserWizardStep控件中,可以添加使用下列特定ID的控件:
q UserName
q Password
q Email
q ConfirmPassword
q Question
q Answer
q ErrorMessage
当然,也可以加入任何其他所需的控件。例如,当新用户注册和将信息保存到特定的数据库表中时,会需要询问一些额外的信息(见 1.3.6 节)。
在CreateUserWizardStep控件中,还可以添加包含了下列CommandName属性值的Button控件:
q CreateUser
q Cancel
1.3.6 在CreateUserWizard控件中添加注册步骤
由于CreateUserWizard控件继承自Wizard基控件。也就是说,在使用CreateUserWizard控件时,可以使用所有Wizard控件支持的属性。尤其是还可以通过添加额外的向导步骤来扩充该CreateUserWizard控件。
例如,假设需要新用户分别输入自己的姓和名。代码清单1-27中的页面包含了一个额外的向导步骤,该步骤包含了填写姓和名的表单项。
代码清单1-27 CreateUserWizardExtra.aspx
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Web.Configuration" %>
<!DOCTYPE html PUBLIC "-//W 3C //DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
{
CreateUserProfile(CreateUserWizard1.UserName,txtFirstName.Text,txtLastName.Text);
}
private void CreateUserProfile(string userName, string firstName, string lastName)
{
string conString = WebConfigurationManager.ConnectionStrings["UserProfiles"].ConnectionString;
SqlConnection con = new SqlConnection(conString);
SqlCommand cmd = new SqlCommand("INSERT UserProfiles (UserName,FirstName,LastName) VALUES
(@UserName,@FirstName,@LastName)", con);
cmd.Parameters.AddWithValue("@UserName", userName);
cmd.Parameters.AddWithValue("@FirstName", firstName);
cmd.Parameters.AddWithValue("@LastName", lastName);
using (con)
{
con.Open();
cmd.ExecuteNonQuery();
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>CreateUserWizard Extra</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:CreateUserWizard
id="CreateUserWizard1"
Runat="server" OnCreatedUser="CreateUserWizard1_CreatedUser">
<WizardSteps>
<asp:WizardStep>
<asp:Label
id="lblFirstName"
Text="First Name:"
AssociatedControlID="txtFirstName"
Runat="server" />
<br />
<asp:TextBox
id="txtFirstName"
Runat="server" />
<br /><br />
<asp:Label
id="lblLastName"
Text="Last Name:"
AssociatedControlID="txtLastName"
Runat="server" />
<br />
<asp:TextBox
id="txtLastName"
Runat="server" />
</asp:WizardStep>
<asp:CreateUserWizardStep />
</WizardSteps>
</asp:CreateUserWizard>
</div>
</form>
</body>
</html>
代码清单1-27中的页面包含了CreatedUser事件的处理函数,创建新用户时将触发该事件。该事件处理函数会将新用户的姓和名添加到数据库表UserProfilesDB中。