【IT168技术文档】
继续前面关于Duwamish的POST,这里将学习Duwamish中关于Password的处理方式。Duwamish 7.0范例中的帐户密码通过SHA1散列运算和对散列执行Salt运算后,是以byte形式存放在Database中,避免明文的方式,以提高系统的安全性。
【用户登录】过程概述
在 Web 层中启动登录过程。用户输入电子邮件地址和密码(凭据),然后单击“Logon”(登录)按钮,这将调用 Duwamish7.Web.Logon.LogonButton_Click 方法。下一步,Duwamish7.Web.Logon.LogonButton_Click 方法创建密码的散列表示形式,并将凭据传递给业务外观层的 Duwamish7.BusinessFacade.CustomerSystem.GetCustomerByEmail 方法。接着 Duwamish7.DataAccess.Customers.LoadCustomerByEmail 方法调用数据访问层,后者又调用 GetCustomerByEmail 存储过程 (SPROC)。然后通过 ComparePasswords 方法,相对于从数据库中检索的经过 salt 和散列运算的密码来验证散列密码。如果凭据有效,则客户帐户信息成功地存储到 Cart 对象,并且 ASP.NET Forms 身份验证通过 pageBase 类 ShoppingCart.Customer() 属性验证凭据。如果凭据无效,则 MismatchLabel 设置为可见,它在 ASP.NET 页上显示下面的内容:“Invalid email address or password- please try again”(电子邮件地址或密码无效,请再试一次)。
下面看看【用户登录】验证功能模块具体的实现代码
(1)Duwamish7.Web.Logon.LogonButton_Click 方法
该方法首先创建用户输入密码的SHA1散列形式,然后调用业务外观层的 Duwamish7.BusinessFacade.CustomerSystem.GetCustomerByEmail 方法。
//
//Check the Email and Password combination
//
SHA1 sha1 = SHA1.Create();
byte [] password = sha1.ComputeHash(Encoding.Unicode.GetBytes
(LogonPasswordTextBox.Text));
custData = (new CustomerSystem()).GetCustomerByEmail
(LogonEmailTextBox.Text, password);
if (custData != null) //were they valid?
{
//
// 1. Update customer in session.
// 2. Update customer in cart.
//
base.Customer = custData;
base.ShoppingCart().Customer = custData;
// 将已验证身份的用户重定向回最初请求的 URL
FormsAuthentication.RedirectFromLoginPage("*", false);
}
else
{
MismatchLabel.Visible = true;
}
如果凭据有效,则客户帐户信息成功地存储到 Cart 对象,并且 ASP.NET Forms 身份验证通过 pageBase 类 ShoppingCart.Customer() 属性验证凭据。如果凭据无效,则 MismatchLabel 设置为可见,它在 ASP.NET 页上显示下面的内容:“Invalid email address or password- please try again”(电子邮件地址或密码无效,请再试一次)
(2)业务外观层的 CustomerSystem.GetCustomerByEmail 方法
根据用户的email,获取Database中Customer的Password,该Password已执行散列运算和对散列执行过Salt运算,是24个字节长度的byte数组。
public CustomerData GetCustomerByEmail
(String emailAddress, byte [] password)
{
//
// Check preconditions
//
ApplicationAssert.CheckCondition(emailAddress != String.Empty,
"Email address is required", ApplicationAssert.LineNumber);
ApplicationAssert.CheckCondition(password.Length != 0,
"Password is required", ApplicationAssert.LineNumber);
//
// Get the customer dataSet
//
CustomerData dataSet;
using (DataAccess.Customers customersDataAccess =
new DataAccess.Customers())
{
dataSet = customersDataAccess.LoadCustomerByEmail(emailAddress);
}
DataRowCollection rows = dataSet.Tables
[CustomerData.CUSTOMERS_TABLE].Rows;
if ( ( rows.Count == 1 ))
{
byte[]dbPassword=(byte[])rows[0][CustomerData.PASSWORD_FIELD];
if (ComparePasswords (dbPassword, password))
return dataSet;
else
return null;
}
else
return null;
}
在获取到DataAccess层返回的CustomerData对象后,进一步调用类中的私有方法ComparePasswords()。该方法负责从Password字段值中提取Salt值,然后运用该Salt值对传入的SHA1散列执行Salt运算。