[翻译]ASP.NET MVC 3 开发的20个秘诀(六)[20 Recipes for Programming MVC 3]:找回忘记的密码

议题

您或者在您网站的注册的某个用户,无法想起自己的密码了,需要有一种方法能找回它。

 

解决方案

在AccountController控制器中添加一个新的动作和视图,以便用户可以找回他们的密码。利用Membership类搜索和匹配用户,并发送一个包含密码的电子邮件。

 

讨论

默认情况下,MVC Internet应用程序使用的是无法逆向转换的单向哈希算法。在下面的例子中,默认是双向散列加密方式。这种方式并不是很安全,但是在用户忘记密码时可以避免强迫用户修改密码。

先在Web.config文件中调整Membership节点的设置: 

<?xml version="1.0"?>
<configuration>
...
<system.web>
...
<membership>
<providers>
<clear />
<add name="AspNetSqlMembershipProvider" type=
"System.Web.Security.SqlMembershipProvider"

connectionStringName
="ApplicationServices"
enablePasswordRetrieval
="true" enablePasswordReset=
"false"
requiresQuestionAndAnswer="false"
requiresUniqueEmail
="false" passwordFormat=
"Encrypted"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength
="6"
minRequiredNonalphanumericCharacters
="0"
passwordAttemptWindow
="10" applicationName="/" />
</providers>
</membership>
<machineKey
validationKey=
"2CF9FF841A23366CFA5D655790D9308656B1F7532C0B95B5C067F80C45E59875
E2F3D68DAC63B5024C31D974D4BE151341FB8A31FC4BC3705DF5398B553FC3C3"

decryptionKey
="8E71407B62F47CCA3AAA6546B3880E1A0EF9833700
E0A0C511710F537E64B8B6"
validation="SHA1" decryption="AES" />
...
</system.web>
...
</configuration>

针对上面的设置代码,我们四个更改:

  1. 将enablePasswordRetrieval更改为True;
  2. 将enablePasswordReset更改为false;
  3. 添加passwordFormat="Encrypted";
  4. 生成加密的machineKey; 

配置信息修改完毕后,在AccountModels.cs类中添加一个新的动作并创建忘记密码的视图:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Security;

namespace MvcApplication4.Models
{
public class ChangePasswordModel
{
...
}
public class LogOnModel
{
...
}
public class RegisterModel
{
...
}
public class ForgotPasswordModel
{
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }
}
}

在创建新视图之前,应用程序必须先编译。单击“生成”->“生成解决方案”或按F6。编译完成之后,展开Views文件夹,右键单击“Account”文件夹,选择“添加”->“视图”(如图1-4)。视图名称更改为“ForgotPassword”,选中“创建强类型视图”选项,从“模型类”下拉框中选择先前创建的“ForgotPasswordModel”,然后点击“添加”。 

视图创建后,添加一个基本的表单,表单接受用户输入注册时填写的电子邮件地址: 

@model MvcApplication4.Models.ForgotPasswordModel
@{

ViewBag.Title = "ForgotPassword";
}

<h2>ForgotPassword</h2>
<p>
Use the form below to retrieve your password.
</p>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {

@Html.ValidationSummary(true, "Password retrieval was unsuccessful. Please correct the errors and try again.")

<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
@Html.LabelFor(m => m.Email)
</div>

<div class="editor-field">
@Html.TextBoxFor(m => m.Email)
@Html.ValidationMessageFor(m => m.Email)
</div>

<p>
<input type="submit" value="Retrieve Password" />
</p>
</fieldset>
</div>
}

下面将在之前创建的MailClient类中添加一个新方法,以实现发送用户忘记的密码: 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Mail;
using System.Net;
using System.Configuration;

namespace MvcApplication4.Utils
{
public class MailClient
{
private static readonly SmtpClient Client;
static MailClient()
{
...
}

private static bool SendMessage(string from, string to,
string subject, string body)
{
...
}

public static bool SendWelcome(string email)
{
...
}

public static bool SendLostPassword(string email,
string password)
{
string body = "Your password is: " + password;
return SendMessage("no-reply@no-reply.com", email,
"Lost Password", body);
}
}
}

这个方法与上一个方法(*译者注:发送欢迎邮件的方法)十分相似,只是又添加了一个参数 --- 用户的密码。这个密码将被添加到电子邮件的内容中并发送给用户。

最后在AccountController中添加两个ForgotPassword方法,第一个方法是默认载入时动作,第二是在用户填写完电子邮件地址后,接受回发数据的动作,他会从数据库中通过搜索并匹配电子邮件地址找到用户,然后将用户密码通过这个地址发给用户。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using MvcApplication4.Models;
using MvcApplication4.Utils;

namespace MvcApplication4.Controllers
{
public class AccountController : Controller
{
...
//
// Get: /Account/ForgotPassword
public ActionResult ForgotPassword()
{
return View();
}

//
// Post: /Account/ForgotPassword
[HttpPost]
public ActionResult ForgotPassword(
ForgotPasswordModel model)
{
if (ModelState.IsValid)
{
MembershipUserCollection users =
Membership.FindUsersByEmail(model.Email);
if (users.Count > 0)
{
foreach (MembershipUser user in users)
{
MailClient.SendLostPassword(model.Email,
user.GetPassword());
}
return RedirectToAction("LogOn");
}
}
// If we got this far, something failed,
// redisplay form
return View(model);
}
...
}

}

在之前的两个秘诀中,只是给用户发送了一些基本信息。将MailMessage的isBodyHtml设置为True,通过简单的扩展增强就可以发送HTML或者更复杂的内容给用户。

 

参考

Membership.Providers Property 原书地址 书籍源代码

posted on 2011-12-10 20:00  O2DS  阅读(2223)  评论(0编辑  收藏  举报

导航