Как правило, большинство крупных сервисов при регистрации требуют ее подтверждения по email. Посмотрим, как сделать подобный механизм в ASP.NET MVC.
В ASP.NET MVC есть несколько моделей авторизации и аутентификации. В данном случае используем механизм авторизации AspNet Identity, так как он более сложен в плане понимания. При использовании других методов аутентификации/авторизации общая схема подтверждения регистрации по email будет аналогична.
Итак, создадим новый проект ASP.NET MVC 5 с типом аутентификации Individual User Accounts. Он по умолчанию содержит весь инструментарий для авторизации: модели, контроллер и представления. Перейдем в папку моделей и откроем файл IdentityModels.cs, который содержит модель ApplicationUser. Изменим эту модель на следующую:
public class ApplicationUser : IdentityUser { public string Email { get; set; } public bool ConfirmedEmail { get; set; } }
К стандартному определению модели мы добавили свойство для email и свойство для хранения значения, подтверждена ли регистрация. Соответственно нам надо изменить модель регистрации RegisterViewModel в файле AccountViewModels.cs, чтобы она принимала дополнительное поле для email:
public class RegisterViewModel { [Required] [Display(Name = "User name")] public string UserName { get; set; } [Required] [Display(Name = "Email")] public string Email { get; set; } [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 = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } }
И также добавим поле для email в представление для регистрации Register.chtml:
<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" }) </div> </div>
Теперь контроллер AccountController, который и производит основную работу. Во-первых, так как нам предстоит отправлять письма, подключим в него необходимое пространство имен:
using System.Net.Mail;
Теперь добавим в AccountController два новых действия и изменим следующим образом действие Register, обрабатывающее post-запросы:
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser() { UserName = model.UserName }; user.Email = model.Email; user.ConfirmedEmail = false; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { // наш email с заголовком письма MailAddress from = new MailAddress("somemail@yandex.ru", "Web Registration"); // кому отправляем MailAddress to = new MailAddress(user.Email); // создаем объект сообщения MailMessage m = new MailMessage(from, to); // тема письма m.Subject = "Email confirmation"; // текст письма - включаем в него ссылку m.Body = string.Format("Для завершения регистрации перейдите по ссылке:" + "<a href=\"{0}\" title=\"Подтвердить регистрацию\">{0}</a>", Url.Action("ConfirmEmail", "Account", new { Token = user.Id, Email = user.Email }, Request.Url.Scheme)); m.IsBodyHtml = true; // адрес smtp-сервера, с которого мы и будем отправлять письмо SmtpClient smtp = new System.Net.Mail.SmtpClient("smtp.yandex.ru", 25); // логин и пароль smtp.Credentials = new System.Net.NetworkCredential("somemail@yandex.ru", "password"); smtp.Send(m); return RedirectToAction("Confirm", "Account", new { Email = user.Email }); } else { AddErrors(result); } } return View(model); } [AllowAnonymous] public string Confirm(string Email) { return "На почтовый адрес " + Email + " Вам высланы дальнейшие" + "инструкции по завершению регистрации"; } [AllowAnonymous] public async Task<ActionResult> ConfirmEmail(string Token, string Email) { ApplicationUser user = this.UserManager.FindById(Token); if (user != null) { if (user.Email == Email) { user.ConfirmedEmail = true; await UserManager.UpdateAsync(user); await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home", new { ConfirmedEmail = user.Email }); } else { return RedirectToAction("Confirm", "Account", new { Email = user.Email }); } } else { return RedirectToAction("Confirm", "Account", new { Email = "" }); } }
По сравнению со стандартным определением метода Register здесь добавлена логика отправки письма стандартными механизмами .NET, которые находятся в пространстве
имен System.Net.Mail
. После отправки посетитель получает на свой адрес письмо с ссылкой, по которой ему надо пройти. Эта ссылка указывает
на метод ConfirmEmail.
После перехода в методе ConfirmEmail обновляется данные пользователя в базе данных: для поля ConfirmedEmail устанавливается значение true, означающее, что пользователь подтвердил регистрацию.
Теперь надо также изменить метод Login, обрабатывющий post-запрос:
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (ModelState.IsValid) { var user = await UserManager.FindAsync(model.UserName, model.Password); if (user != null) { if (user.ConfirmedEmail == true) { await SignInAsync(user, model.RememberMe); return RedirectToLocal(returnUrl); } else { ModelState.AddModelError("", "Не подтвержден email."); } } else { ModelState.AddModelError("", "Неверный логин или пароль"); } } return View(model); }
Теперь при логине будет учитываться, подтвердил ли ранее пользователь свой email.