沒有第二種形式的身份驗證(例如確認的電子郵件地址,電話號碼,安全問題,PIN等)的用戶不能信任密碼重置。
如果您再次遇到這個問題,我認爲最好的解決方案是在用戶登錄後提醒用戶他們沒有經過確認的電子郵件,並且他們可能會失去對其帳戶的訪問權限不及時確認電子郵件。這仍然會讓一些固執的用戶不幸運,他們拒絕確認電子郵件並丟失密碼,但在這種情況下,您可以根據具體情況使用較小的用戶羣。
要完成上述建議的解決方案,您可以從登錄後立即提醒用戶注意缺少電子郵件,其中包括在Account
控制器中創建重定向。以下是Visual Studio在創建新的ASP.NET 4.5.2 MVC Web應用程序時生成的股票登錄方法的修改版本。請特別注意SignInStatus.Success
的情況,它會重定向到我創建的名爲RequestEmailConfirmation
的新控制器操作。
控制器/ AccountController.cs:
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
// Redirect user to confirm an email address.
if (!(await UserManager.IsEmailConfirmedAsync(User.Identity.GetUserId())))
{
return RedirectToAction("RequestEmailConfirmation", "Account");
}
else
{
return RedirectToLocal(returnUrl);
}
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
// GET: /Account/RequestEmailConfirmation
public ActionResult RequestEmailConfirmation()
{
return View();
}
此修改登錄操作將忽略任何returnUrl
用戶可能有。如果需要,可以維護該信息,但對於此示例,如果用戶被重定向以確認電子郵件,則會丟失該信息。
接下來,我們看一個新的視圖頁面和一個視圖模型,以配合RequestEmailConfirmation
操作。該視圖爲用戶提供了一個簡單的表單,用於鍵入並重新鍵入他們的電子郵件,並且視圖模型存儲該信息以傳遞給我們稍後將看到的另一個控制器操作。請注意,此時用戶已登錄並可選擇忽略電子郵件確認請求,而不是導航到網站上的其他密碼保護內容。
查看/帳號/ RequestEmailConfirmation.cshtml
@using MyWebApplication.Models
@model RequestEmailConfirmationViewModel
@{
ViewBag.Title = "Request Email Confirmation";
}
<h2>@ViewBag.Title.</h2>
<div class="row">
<div class="col-md-8">
<section id="loginForm">
@using (Html.BeginForm("RequestEmailConfirmation", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<h4>Confirm Email Address</h4>
<span class="text-danger">You have not yet confirmed an email address for this account. Please confirm your email address below to ensure access to your account in the event of a lost or forgotten password.</span>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.ConfirmEmail, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.ConfirmEmail, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.ConfirmEmail, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Confirm" class="btn btn-default" />
</div>
</div>
}
</section>
</div>
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
型號/ RequestEmailConfirmationViewModel.cshtml:
using System.ComponentModel.DataAnnotations;
namespace MyWebApplication.Models
{
public class RequestEmailConfirmationViewModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email")]
public string Email { get; set; }
[DataType(DataType.EmailAddress)]
[Display(Name = "Confirm Email")]
[Compare("Email", ErrorMessage = "The email and confirmation email do not match.")]
public string ConfirmEmail { get; set; }
}
}
有了電子郵件確認申請表,我們繼續在三個控制器動作Account
控制器處理表單提交,「感謝您提交確認電子郵件」頁面,以及當用戶訪問確認電子郵件中提供的鏈接時處理確認電子郵件的操作。這裏的重要部分是電子郵件確認令牌生成以及該令牌收據的後續確認,這可以讓我們安全地設置用戶數據庫中的EmailConfirmed
值。下面還創建了兩個新視圖,第一個顯示「謝謝您提交確認電子郵件」消息,第二個顯示「謝謝您確認您的電子郵件」消息。
控制器/ AccountController.cs(續):
// POST: /Account/Register
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> RequestEmailConfirmation(RequestEmailConfirmationViewModel model)
{
if (ModelState.IsValid)
{
// Send an email confirmation.
string userId = User.Identity.GetUserId();
string code = await UserManager.GenerateEmailConfirmationTokenAsync(userId);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = userId, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Confirm Email Address", "Please confirm your email address by clicking <a href=\"" + callbackUrl + "\">here</a>.");
return RedirectToAction("RequestEmailConfirmationSubmitted", "Home");
}
// If we got this far, something failed, redisplay form
return View(model);
}
// GET: /Account/RequestEmailConfirmationSubmitted
[AllowAnonymous]
public ActionResult RequestEmailConfirmationSubmitted()
{
return View();
}
// GET: /Account/ConfirmEmail
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return View("Error");
}
var result = await UserManager.ConfirmEmailAsync(userId, code);
return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
查看/帳號/ RequestEmailConfirmationSubmitted.cshtml
@{
ViewBag.Title = "Email Address Submitted";
}
<h2>@ViewBag.Title.</h2>
<div>
<p>
Thank you for submitting your email address. An email with a confirmation link will be sent to you shortly to verify your ownership.
</p>
</div>
查看/帳號/ ConfirmEmail.cshtml:
@{
ViewBag.Title = "Email Address Confirmed";
}
<h2>@ViewBag.Title.</h2>
<div>
<p>
Thank you for confirming your email.
</p>
</div>
通過上面的代碼,我假設您已經設置了一個電子郵件服務來實際發送確認電子郵件給用戶。一旦用戶確認了他們的電子郵件,他們將能夠安全地使用密碼重置功能。雖然我沒有完全測試過這些代碼,但是這應該爲您提供解決問題的充分方法。
這聽起來像是一個很好的解決方案,但我在詢問有關如何實現它的信息。我明白爲什麼密碼重置僅限於已確認的電子郵件,並且我明白,您的建議是解決方案的一種好方法。請隨時添加一些關於如何去做的有用的技術信息。 – trademark
@trademark完成。 – Chase