「WebMatrix.WebData.WebSecurity を利用したユーザー認証(その1)」の続きです。翌日にでも書こうかと思っていたのですが、一週間後になってしまいました
前回の記事で「利用者登録」と「ログイン」まで作成済みなので、今回は「パスワードの再発行」と「パスワードの変更」部分を作ります。
「パスワードの再発行」は次のような動きになります。
送られてきたメールの本文にある「パスワード・リセットを行うページ」へのリンクをクリックするとブラウザに「新しいパスワードの入力画面」が開き、新しいパスワードをセットすることができます。
プログラムは、まずモデル AccountModels.cs から。
namespace TestAuthorize002.Models
{
~略~
public class ForgotPasswordModel
{
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "登録したメールアドレスを入力してください。")]
public string Email { get; set; }
}
public class ResetPasswordModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "パスワードと確認のパスワードが一致しません。")]
public string ConfirmPassword { get; set; }
public string ResetToken { get; set; }
}
}
次に、コントローラー AccountController.cs です。
namespace TestAuthorize002.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)
{
return View(model);
}
var resetToken = "";
if (WebSecurity.GetUserId(model.Email) > -1 && WebSecurity.IsConfirmed(model.Email))
resetToken = WebSecurity.GeneratePasswordResetToken(model.Email);
else
{
ModelState.AddModelError("Email", "このメールアドレスは登録されていないか、未確認状態のためパスワードのリセットはできません。");
return View();
}
var hostUrl = Request.Url.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped);
var resetUrl = hostUrl + VirtualPathUtility.ToAbsolute("~/Account/PasswordReset?resetToken=" +
HttpUtility.UrlEncode(resetToken));
try
{
var mail = new SmtpMailMessage
{
From = new System.Net.Mail.MailAddress("送信元のメールアドレスを記入"),
To = new System.Net.Mail.MailAddress(model.Email),
Subject = "パスワード・リセットに必要な情報",
Body = "パスワード・リセットのトークン: " + resetToken + "\r\n" +
"パスワード・リセットを行うページ <" + resetUrl + "> " +
"を訪問して、パスワードのリセットを行ってください。"
};
SmtpMail.Send(mail);
}
catch (ApplicationException ex)
{
ModelState.AddModelError("", "メールが送れませんでした。エラー内容: " + ex.Message);
return View();
}
catch (System.Net.Sockets.SocketException ex)
{
ModelState.AddModelError("", "メール送信サーバーと接続ができませんでした。エラー内容: " + ex.Message);
return View();
}
catch (System.Security.Authentication.AuthenticationException ex)
{
ModelState.AddModelError("", "メールサーバーと SSL 接続ができませんでした。エラー内容: " + ex.Message);
return View();
}
catch (System.Web.Security.MembershipCreateUserException e)
{
ModelState.AddModelError("", e.ToString());
return View();
}
TempData["title"] = "メールを送りました";
TempData["message"] = "パスワードリセットに必要な情報をメールで送りました。";
return RedirectToAction("Done");
}
//
// GET: /Account/Done
public ActionResult Done()
{
return View();
}
//
// GET: /Account/PasswordReset
public ActionResult PasswordReset(string resetToken)
{
if (string.IsNullOrEmpty(resetToken))
{
TempData["message"] = "パスワードリセットが要求されましたが、パスワード・リセット・トークンが不正です。";
return RedirectToAction("Error");
}
var model = new ResetPasswordModel
{
ResetToken = resetToken
};
return View(model);
}
//
// POST: /Account/PasswordReset
[HttpPost]
public ActionResult PasswordReset(ResetPasswordModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
if (!WebSecurity.ResetPassword(model.ResetToken, model.Password))
{
TempData["message"] = "パスワードリセットが要求されましたが、" +
"パスワード・リセット・トークンが誤っているため、リセット出来ませんでした。";
return RedirectToAction("Error");
}
TempData["title"] = "パスワードをリセットしました";
TempData["message"] = "新しいパスワードでログオンしてください。";
return RedirectToAction("Done");
}
//
// GET: /Account/Error
public ActionResult Error()
{
return View();
}
View は新規作成が4つです。
Done.cshtml(厳密に型指定されたビューを作成する のチェックなし)
@{
ViewBag.Title = TempData["title"];
}
<h2>@TempData["title"]</h2>
<p>@Html.Encode(TempData["message"])</p>
Error.cshtml(厳密に型指定されたビューを作成する のチェックなし)
@{
ViewBag.Title = "要求は処理できませんでした";
}
<h2>要求は処理できませんでした</h2>
<p>@TempData["message"]</p>
ForgotPassword.cshtml(厳密に型指定されたビューを作成する のチェックあり:ForgotPasswordModel (TestAuthorize002.Models), Create)
@model TestAuthorize002.Models.ForgotPasswordModel
@{
ViewBag.Title = "パスワードのリセット";
}
<h2>パスワードのリセット</h2>
<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)
<fieldset>
<legend>パスワードのリセット</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Email)
@Html.ValidationMessageFor(model => model.Email)
</div>
<p>
<input type="submit" value="リセット" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
PasswordReset.cshtml(厳密に型指定されたビューを作成する のチェックあり:ResetPasswordModel (TestAuthorize002.Models), Create)
@model TestAuthorize002.Models.ResetPasswordModel
@{
ViewBag.Title = "PasswordReset";
}
<h2>PasswordReset</h2>
<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)
<fieldset>
<legend>ResetPasswordModel</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Password)
@Html.ValidationMessageFor(model => model.Password)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ConfirmPassword)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ConfirmPassword)
@Html.ValidationMessageFor(model => model.ConfirmPassword)
</div>
<div class="editor-field">
@Html.HiddenFor(model => model.ResetToken)
</div>
<p>
<input type="submit" value="リセット" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
これで前回と併せて WebMatrix を利用した「利用者登録」「ログイン」「パスワードのリセット」「パスワードの変更」ができるようになりました。
貴重な情報ありがとうございました。SmtpOverSslもダウンロードさせてもらいました。上記のウェブサイトはMVC4のテスト用なのですがばっちり動作してます。ありがとうございました。
コメントありがとうございます。
この情報が役に立ったということで、コチラとしても嬉しいです 🙂