1.4 使用LoginStatus控件
根据当前用户的认证状态,LoginStatus控件将显示为一个登录(Login)或注销(Logout)链接。当用户点击登录链接后,会跳转到页面Login.aspx中。而点击注销链接,将会从该网站中注销该次登录。
代码清单1-28中的页面包含了一个LoginStatus控件(见图1-11)。
图1-11 使用LoginStatus控件显示用户登录链接
代码清单1-28 ShowLoginStatus.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 LoginStatus</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LoginStatus
id="LoginStatus1"
Runat="server" />
<hr />
Additional information is available to registered users. Log in to view
the additional information.
</div>
</form>
</body>
</html>
访问代码清单1-28中的页面时,如果点击了登录链接,用户的访问请求将会重定向到页面Login.aspx上。如果这时输入并提交了有效的用户名和密码,访问请求就会再次重定向回页面ShowLoginStatus.aspx。
LoginStatus控件支持下列属性:
q LoginImageUrl——用于为登录链接指定一个图片;
q LoginText——用于为登录链接指定文字;
q LogoutAction——用于在点击注销链接后发生的页面导航动作。可能的取值为:Redirect、Redirect- ToLoginPage和Refresh;
q LogoutImageUrl——用于为注销链接指定一个图片;
q LogoutPageUrl——用于指定用户注销后返回的页面的路径。只有当LogoutAction属性的值为Redirect时,该属性才会生效;
q LogoutText——用于为注销链接指定文字。
LoginStatus控件还支持下列事件:
q LoggingOut——在用户进行注销登录之前触发;
q LoggedOut——在用户进行注销登录之后触发。
1.5 使用LoginName控件
LoginName控件将显示当前登录用户的注册用户名。如果当前用户未通过认证,那么LoginName控件不会输出任何内容。
代码清单1-29中页面包含了LoginName和LoginStatus两个控件。
代码清单1-29 ShowLoginName.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 LoginName</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LoginName
id="LoginName1"
FormatString="{0} /"
Runat="server" />
<asp:LoginStatus
id="LoginStatus1"
Runat="server" />
<hr />
Additional information is available to registered users. Log in to view
the additional information.
</div>
</form>
</body>
</html>
在首次访问代码清单1-29中的页面时,LoginName控件不会输出任何内容。然而,如果通过点击登录链接登录了该网站,那么LoginName控件将输出当前登录网站的用户名(见图1-12)。
图1-12 使用LoginName控件显示当前用户名
LoginName控件支持下列属性:
q FormatString —— 用于在控件输出用户名时对其格式进行定制。
1.6 使用ChangePassword控件
用户(或系统管理员)可以通过ChangePassword控件来修改用户密码。代码清单1-30中的页面展示了如何使用该控件。
代码清单1-30 ShowChangePassword.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">
.changePassword
{
font:14px Verdana,Sans-Serif;
background-color:lightblue;
border:solid 3px black;
padding:4px;
}
.changePassword_title
{
background-color:darkblue;
color:white;
font-weight:bold;
}
.changePassword_instructions
{
font-size:12px;
text-align:left;
padding:10px;
}
.changePassword_button
{
border:solid 1px black;
padding:3px;
}
</style>
<title>Show ChangePassword</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LoginName ID="LoginName1" runat="server" />
<asp:ChangePassword
id="ChangePassword1"
InstructionText="Complete this form to create
a new password."
DisplayUserName="true"
ContinueDestinationPageUrl="~/Default.aspx"
CancelDestinationPageUrl="~/Default.aspx"
CssClass="changePassword"
TitleTextStyle-CssClass="changePassword_title"
InstructionTextStyle-CssClass="changePassword_instructions"
ChangePasswordButtonStyle-CssClass="changePassword_button"
CancelButtonStyle-CssClass="changePassword_button"
ContinueButtonStyle-CssClass="changePassword_button"
Runat="server" />
</div>
</form>
</body>
</html>
代码清单1-30中的表单包含了输入用户名、旧密码、新密码和新密码确认四个表单项(见图1-13)。该表单提交后,用户的旧密码将更改为新密码。
需要注意的是,代码清单1-29中的ChangePassword控件包含了一个DisplayUserName属性。当启用这个属性后,控件将会输出用户名表单项。当在Web应用程序页面中放置密码保护项时,不需要包含DisplayUserName属性。因为在该示例中,ChangePassword控件将自动使用当前用户的名称。
图1-13 使用ChangePassword控件修改用户密码
1.6.1 发送电子邮件通知密码更改
当用户修改了密码后,可以通过该ChangePassword控件自动发送一封包含了新密码的电子邮件通知。代码清单1-31中的页面即包含了用于自动发送电子邮件通知的ChangePassword控件。
注解 即使用户的密码通过Membership提供器进行了加密或散列,仍然可以通过电子邮件通知进行发送。
代码清单1-31 ChangePasswordEmail.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>ChangePassword Email</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ChangePassword
id="ChangePassword1"
DisplayUserName="true"
Runat="server">
<MailDefinition
From="Admin@YourSite.com"
BodyFileName="ChangePassword.txt"
Subject="Your New Password" />
</asp:ChangePassword>
</div>
</form>
</body>
</html>
需要注意的是,代码清单1-31中的ChangePassword控件包含了一个MailDefinition属性,该属性用于定义ChangePassword控件将发送的电子邮件通知。代码清单1-32中的文本文件包含了该ChangePassword控件发送的电子邮件通知的内容。
代码清单1-32 ChangePassword.txt
<%UserName%>,
your new password is <%Password%>.
代码清单1-32中的电子邮件通知包含了两个特殊的表达式:<% UserName %>和<% Password %>。当发送电子邮件时,这两个表达式将使用该用户的用户名和密码来进行替换。
注解 MailDefinition类使用Web配置文件中smtp节点配置的电子邮件服务器端。要了解更多关于smtp节点的配置信息,可以见 1.3.2 节。
1.6.2 在ChangePassword控件中使用模板
如果要彻底修改ChangePassword控件的外观,那么可以使用模板来对该控件进行定制。ChangePassword控件支持ChangePasswordTemplate和SuccessTemplate两类模板。
代码清单1-33中的页面示例了如何使用ChangePassword控件所支持的这两类模板(见图1-14)。
图1-14 使用模板来自定义ChangePassword控件
代码清单1-33 ChangePasswordTemplate.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>ChangePassword Template</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ChangePassword
id="ChangePassword1"
DisplayUserName="true"
Runat="server">
<ChangePasswordTemplate>
<h1>Change Password</h1>
<asp:Label
id="FailureText"
EnableViewState="false"
ForeColor="Red"
Runat="server" />
<br />
<asp:Label
id="lblUserName"
Text="User Name:"
AssociatedControlID="UserName"
Runat="server" />
<br />
<asp:TextBox
id="UserName"
Runat="server" />
<br /><br />
<asp:Label
id="lblCurrentPassword"
Text="Current Password:"
AssociatedControlID="CurrentPassword"
Runat="server" />
<br />
<asp:TextBox
id="CurrentPassword"
TextMode="Password"
Runat="server" />
<br /><br />
<asp:Label
id="lblNewPassword"
Text="New Password:"
AssociatedControlID="NewPassword"
Runat="server" />
<br />
<asp:TextBox
id="NewPassword"
TextMode="Password"
Runat="server" />
<br /><br />
<asp:Button
id="btnChangePassword"
Text="Change Password"
CommandName="ChangePassword"
Runat="server" />
</ChangePasswordTemplate>
<SuccessTemplate>
Your password has been changed!
</SuccessTemplate>
</asp:ChangePassword>
</div>
</form>
</body>
</html>
可以在ChangePasswordTemplate模板中使用以下特定ID的控件:
q UserName
q CurrentPassword
q ConfirmPassword
q NewPassword
q FailureText
同时还可以添加具有以下CommandName属性值的Button控件:
q ChangePassword
q Cancel
q Continue
1.7 使用PasswordRecovery控件
如果用户忘记了自己的登录密码,那么可以使用PasswordRecovery控件将密码找回。通过PasswordRecovery控件不但可以找回用户的原始密码,也可以对密码进行重置后再将新密码发送给用户。
代码清单1-34中的页面包含了一个PasswordRecovery控件。
代码清单1-34 ShowPasswordRecovery.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">
.passwordRecovery
{
font:14px Verdana,Sans-Serif;
background-color:lightblue;
border:solid 3px black;
padding:4px;
}
.passwordRecovery_title
{
background-color:darkblue;
color:white;
font-weight:bold;
}
.passwordRecovery_instructions
{
font-size:12px;
text-align:left;
padding:10px;
}
.passwordRecovery_button
{
border:solid 1px black;
padding:3px;
}
</style>
<title>Show PasswordRecovery</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PasswordRecovery
id="PasswordRecovery1"
CssClass="passwordRecovery"
TitleTextStyle-CssClass="passwordRecovery_title"
InstructionTextStyle-CssClass="passwordRecovery_instructions"
SubmitButtonStyle-CssClass="passwordRecovery_button"
Runat="server">
<MailDefinition
From="Admin@YourSite.com"
Subject="Password Reminder" />
</asp:PasswordRecovery>
</div>
</form>
</body>
</html>
在网页浏览器中访问代码清单1-34中的页面时,会出现一个要求输入用户名的表单提示框(见图1-15)。接下来,需要回答当初注册该用户时所输入的安全提示问题。如果安全提示问题回答正确,该用户的密码就会发送到用户注册信息中的电子邮件地址中。
在默认情况下,PasswordRecovery控件会首先重置用户的密码,再发送其自动生成的新密码。在下一节中,将介绍如何通过该控件找回用户的原始密码。
图1-15 通过PasswordRecovery控件找回丢失密码
注解 在使用PasswordRecovery控件之前,必须在该应用程序的Web配置文件中指定控件所使用的电子邮件服务设置。详细配置信息见 1.3.2 节。
1.7.1 找回用户的原始密码
在默认情况下,PasswordRecovery控件不会发送用户的原始密码。如果不希望在发送密码之前自动重置用户的密码,那么就必须改变Membership接口提供器的配置。其中三个相关的配置设置是passwordFormat、enablePasswordRetrieval和enablePasswordReset。
属性PasswordRecovery的默认值是Hashed。当密码被散列后,PasswordRecovery控件就不能发送用户的原始密码了,并且任何地方都不会保存有原始密码。从保护秘密安全的角度来看,这个限制是很有意义的。如果希望系统能向用户发送原始密码,那么就需要将passwordFormat属性设置为Clear或者Encrypted。
属性enablePasswordRetrieval的默认值是false。因此,如果希望向用户发送其原始密码,还必须在Web配置文件中启用这个属性。
最后,属性enablePasswordReset的默认值是true。不管属性passwordFormat或属性enablePassword- Retrieval的取值是什么,通过enablePasswordReset属性都能够重置用户的密码,并由电子邮件将新密码发送给用户。
允许发送用户原始密码的必要配置信息包含在代码清单1-35中的Web配置文件中。
代码清单1-35 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"
passwordFormat="Clear"
enablePasswordRetrieval="true"
/>
</providers>
</membership>
</system.web>
</configuration>
代码清单1-35中的配置文件将以明文形式而非散列方式存储用户的密码。此外,该配置清单还启用了密码找回功能。
1.7.2 要求安全提示问题和答案
使用CreateUserWizard控件进行注册时,会要求填写一个安全提示问题及答案。PasswordRecovery控件将会显示一个包含安全提示问题的表单。如果不能提交正确的问题答案,系统就不会发送密码。
如果在进行找回密码操作时,并不希望用户回答安全提示问题,那么就修改Membership接口提供器的配置。代码清单1-36中Web配置文件的requiresQuestionAndAnswer属性就设置为false。
代码清单1-36 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"
/>
</providers>
</membership>
</system.web>
</configuration>
1.7.3 在PasswordRecovery控件中使用模板
如果你希望能完全自定义PasswordRecovery控件的外观,那么就需要使用模板。PasswordRecovery控件支持下列三类模板:
q UserNameTemplate
q QuestionTemplate
q SuccessTemplate
代码清单1-37中的页面展示了如何使用这三类模板。
代码清单1-37 PasswordRecoveryTemplate.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">
html
{
font:12px Arial,Sans-Serif;
}
h1
{
font:bold 16px Arial,Sans-Serif;
color:DarkGray;
}
</style>
<title>PasswordRecovery Template</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PasswordRecovery
id="PasswordRecovery1"
Runat="server">
<MailDefinition
From="Admin@YourSite.com"
Subject="Password Reminder"
BodyFileName="PasswordRecovery.txt" />
<UserNameTemplate>
<h1>User Name</h1>
<asp:Label
id="FailureText"
EnableViewState="false"
ForeColor="Red"
Runat="server" />
<br />
<asp:Label
id="lblUserName"
Text="Enter your user name:"
AssociatedControlID="UserName"
Runat="server" />
<br />
<asp:TextBox
id="UserName"
Runat="server" />
<br />
<asp:Button
id="btnSubmit"
Text="Next"
CommandName="Submit"
Runat="server" />
</UserNameTemplate>
<QuestionTemplate>
<h1>Security Question</h1>
<asp:Label
id="FailureText"
EnableViewState="false"
ForeColor="Red"
Runat="server" />
<br />
<asp:Label
id="Question"
Text="Enter your user name:"
AssociatedControlID="Answer"
Runat="server" />
<br />
<asp:TextBox
id="Answer"
Runat="server" />
<br />
<asp:Button
id="btnSubmit"
Text="Next"
CommandName="Submit"
Runat="server" />
</QuestionTemplate>
<SuccessTemplate>
<h1>Success</h1>
An email has been sent to your registered
email account that contains your user name
and password.
</SuccessTemplate>
</asp:PasswordRecovery>
</div>
</form>
</body>
</html>
UserNameTemplate中必须包含一个ID为UserName的控件。如果要显示错误提示信息,那么还需要包含一个ID为FailureText的文本显示控件。该模板还必须包含一个CommandName值为Submit的Button控件。
QuestionTemplate中必须包含ID分别为Question和Answer的两个控件。作为可选的设置项,如果要显示错误提示信息,那么就要包含一个ID为FailureText的文本显示控件。这个模板也必须包含一个CommandName值为Submit的Button控件。
而SuccessTemplate模板则不需要专门指定任何含有特定属性值的控件。
需要注意的是,代码清单1-37中的PasswordRecovery控件包含了用来指定自定义电子邮件通知信息的MailDefinition属性,该邮件通知信息包含在代码清单1-38中的文本文件中。
代码清单1-38 PasswordRecovery.txt
Here's your login information:
user name: <%UserName%>
password: <%Password%>
1.8 使用LoginView控件
根据不同用户的认证状态,LoginView控件可以用于显示不同的内容。例如,代码清单1-39中的页面将分别为认证用户和匿名用户显示不同的内容(见图1-16)。
图1-16 通过LoginView控件为认证用户显示指定内容
代码清单1-39中的LoginView控件包含了两个模板:AnonymousTemplate模板和LoggedInTemplate模板,在同一时刻只能显示其中一个。
代码清单1-39 ShowLoginView.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 LoginView</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LoginStatus
id="LoginStatus"
Runat="server" />
<hr />
<asp:LoginView
id="LoginView1"
Runat="server">
<AnonymousTemplate>
This content is displayed to anonymous users.
</AnonymousTemplate>
<LoggedInTemplate>
This content is displayed to authenticated users.
</LoggedInTemplate>
</asp:LoginView>
</div>
</form>
</body>
</html>
该页面中还包含了一个LoginStatus控件,使用它可以快速地登录和登出应用程序。
注解 LoginView控件在使用Windows认证时也能像使用Forms认证一样工作。
在LoginView控件中使用角色
对属于不同角色的不同用户,也可以通过使用LoginView控件来为其分别显示不同的内容。代码清单1-40中的页面包含了一个LoginView控件,该控件包含两个RoleGroup控件。第一个RoleGroup控件含有为管理员组(Administrator)成员显示的内容,第二个则包含为工作人员组(Worker)成员显示的内容。
代码清单1-40 LoginViewRoles.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)
{
MembershipCreateStatus status;
// Create Bill
Membership.CreateUser("Bill","secret_","bill@somewhere.com","dog","rover",true,out status);
// Create Ted
Membership.CreateUser("Ted", "secret_", "ted@somewhere.com", "dog", "rover", true,out status);
// Create Fred
Membership.CreateUser("Fred", "secret_", "fred@somewhere.com", "dog", "rover", true, out status);
// Create Administrator Role
if (!Roles.RoleExists("Administrator"))
{
Roles.CreateRole("Administrator");
Roles.AddUserToRole("Bill", "Administrator");
}
// Create Manager Role
if (!Roles.RoleExists("Manager"))
{
Roles.CreateRole("Manager");
Roles.AddUserToRole("Bill", "Manager");
Roles.AddUserToRole("Ted", "Manager");
}
// Create Worker Role
if (!Roles.RoleExists("Worker"))
{
Roles.CreateRole("Worker");
Roles.AddUserToRole("Fred", "Worker");
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>LoginView Roles</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LoginStatus
id="LoginStatus"
Runat="server" />
<hr />
<asp:LoginView
id="LoginView1"
Runat="server">
<RoleGroups>
<asp:RoleGroup Roles="Administrator">
<ContentTemplate>
This content is displayed to Administrators.
</ContentTemplate>
</asp:RoleGroup>
<asp:RoleGroup Roles="Manager,Worker">
<ContentTemplate>
This content is displayed to Managers
and Workers.
</ContentTemplate>
</asp:RoleGroup>
</RoleGroups>
</asp:LoginView>
</div>
</form>
</body>
</html>
代码清单1-40中的事件处理函数Page_Load()创建了名为Bill、Ted和Fred的三个用户。Bill加入了管理员和经理组(Manager),Ted加入了经理组,而Fred加入了工作人员组。
在同一时刻,LoginView控件只能显示一个RoleGroup所对应的内容。如果同一个用户属于多个RoleGroup,那么将显示第一个匹配的RoleGroup所对应的内容,而其他RoleGroup对应的内容将被忽略。
代码清单1-41 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<authentication mode="Forms" />
<roleManager enabled="true" />
</system.web>
</configuration>