Oturum açma, e-posta onayı ve parola sıfırlama özellikli, güvenli bir ASP.NET MVC 5 web uygulaması oluşturma (C#)
tarafından Rick Anderson
Bu öğreticide, ASP.NET Kimlik üyelik sistemini kullanarak e-posta onayı ve parola sıfırlama ile bir ASP.NET MVC 5 web uygulaması oluşturma işlemi gösterilmektedir.
Bu öğreticinin .NET Core kullanan güncelleştirilmiş bir sürümü için bkz . ASP.NET Core'da hesap onayı ve parola kurtarma.
ASP.NET MVC uygulaması oluşturma
Web veya Visual Studio 2013 için Visual Studio Express 2013'i yükleyip çalıştırarak başlayın. Visual Studio 2013 Güncelleştirme 3 veya üzerini yükleyin.
Not
Uyarı: Bu öğreticiyi tamamlamak için Visual Studio 2013 Güncelleştirme 3 veya üzerini yüklemeniz gerekir.
Yeni bir ASP.NET Web projesi oluşturun ve MVC şablonunu seçin. Web Forms, ASP.NET Kimliğini de desteklediği için bir web formları uygulamasında benzer adımları izleyebilirsiniz.
Varsayılan kimlik doğrulamasını Tek Tek Kullanıcı Hesapları olarak bırakın. Uygulamayı Azure'da barındırmak istiyorsanız onay kutusunu işaretli bırakın. Öğreticinin ilerleyen bölümlerinde Azure'a dağıtacağız. Bir Azure hesabını ücretsiz olarak açabilirsiniz.
Projeyi SSL kullanacak şekilde ayarlayın.
Uygulamayı çalıştırın, Kaydet bağlantısına tıklayın ve bir kullanıcı kaydedin. Bu noktada, e-postadaki tek doğrulama [EmailAddress] özniteliğiyle yapılır.
Sunucu Gezgini'nde Veri Bağlantıları\DefaultConnection\Tables\AspNetUsers'a gidin, sağ tıklayın ve Tablo tanımını aç'ı seçin.
Aşağıdaki görüntüde şema gösterilmektedir
AspNetUsers
:AspNetUsers tablosuna sağ tıklayın ve Tablo Verilerini Göster'i seçin.
Bu noktada e-posta onaylanmamıştır.Satıra tıklayın ve sil'i seçin. Sonraki adımda bu e-postayı yeniden ekleyeceksiniz ve bir onay e-postası göndereceksiniz.
E-posta onayı
Başka birinin kimliğine bürünmediklerini (başka birinin e-postasına kaydolmadığını) doğrulamak için yeni bir kullanıcı kaydının e-postasını onaylamak en iyi yöntemdir. Bir tartışma forumun olduğunu varsayalım, olarak "joe@contoso.com"
kaydolmasını engellemek "bob@example.com"
istersiniz. E-posta onayı olmadan, "joe@contoso.com"
uygulamanızdan istenmeyen e-postalar alabilirsiniz. Bob'un yanlışlıkla olarak "bib@example.com"
kaydolduğunu ve bunu fark etmediğini varsayalım; uygulamada doğru e-posta adresi olmadığından parola kurtarmayı kullanamayacaktır. E-posta onayı, botlara karşı yalnızca sınırlı koruma sağlar ve belirlenen spam gönderenlere karşı koruma sağlamaz, kaydolmak için kullanabilecekleri birçok çalışma e-posta diğer adına sahiptir.
Genellikle yeni kullanıcıların e-posta, SMS kısa mesajı veya başka bir mekanizmayla onaylanana kadar web sitenize herhangi bir veri göndermesini engellemek istersiniz. Aşağıdaki bölümlerde, e-posta onayını etkinleştirecek ve yeni kaydedilen kullanıcıların e-postaları onaylanana kadar oturum açmalarını önlemek için kodu değiştireceğiz.
SendGrid'i bağlama
Bu bölümdeki yönergeler geçerli değil. Güncelleştirilmiş yönergeler için bkz . SendGrid e-posta sağlayıcısını yapılandırma.
Bu öğretici yalnızca SendGrid aracılığıyla e-posta bildirimi eklemeyi gösterse de, SMTP ve diğer mekanizmaları kullanarak e-posta gönderebilirsiniz (ek kaynaklara bakın).
Paket Yöneticisi Konsolu'nda aşağıdaki komutu girin:
Install-Package SendGrid
Azure SendGrid kayıt sayfasına gidin ve ücretsiz bir SendGrid hesabına kaydolun. App_Start/IdentityConfig.cs aşağıdakine benzer bir kod ekleyerek SendGrid'i yapılandırın:
public class EmailService : IIdentityMessageService { public async Task SendAsync(IdentityMessage message) { await configSendGridasync(message); } // Use NuGet to install SendGrid (Basic C# client lib) private async Task configSendGridasync(IdentityMessage message) { var myMessage = new SendGridMessage(); myMessage.AddTo(message.Destination); myMessage.From = new System.Net.Mail.MailAddress( "Joe@contoso.com", "Joe S."); myMessage.Subject = message.Subject; myMessage.Text = message.Body; myMessage.Html = message.Body; var credentials = new NetworkCredential( ConfigurationManager.AppSettings["mailAccount"], ConfigurationManager.AppSettings["mailPassword"] ); // Create a Web transport for sending email. var transportWeb = new Web(credentials); // Send the email. if (transportWeb != null) { await transportWeb.DeliverAsync(myMessage); } else { Trace.TraceError("Failed to create Web transport."); await Task.FromResult(0); } } }
Aşağıdakileri eklemeniz gerekir:
using SendGrid;
using System.Net;
using System.Configuration;
using System.Diagnostics;
Bu örneği basit tutmak için uygulama ayarlarını web.config dosyasında depolayacağız:
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<!-- Markup removed for clarity. -->
<add key="mailAccount" value="xyz" />
<add key="mailPassword" value="password" />
</appSettings>
<system.web>
Uyarı
Güvenlik : Hassas verileri hiçbir zaman kaynak kodunuzda depolamayın. Hesap ve kimlik bilgileri appSetting içinde depolanır. Azure'da, bu değerleri Azure portalındaki Yapılandır sekmesinde güvenli bir şekilde depolayabilirsiniz. Bkz. Parolaları ve diğer hassas verileri ASP.NET ve Azure'a dağıtmak için en iyi yöntemler.
Hesap denetleyicisinde e-posta onayını etkinleştirme
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account",
new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id,
"Confirm your account", "Please confirm your account by clicking <a href=\""
+ callbackUrl + "\">here</a>");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Views\Account\ConfirmEmail.cshtml dosyasının doğru razor söz dizimine sahip olduğunu doğrulayın. ( İlk satırdaki @ karakteri eksik olabilir. )
@{
ViewBag.Title = "Confirm Email";
}
<h2>@ViewBag.Title.</h2>
<div>
<p>
Thank you for confirming your email. Please @Html.ActionLink("Click here to Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })
</p>
</div>
Uygulamayı çalıştırın ve Kaydet bağlantısına tıklayın. Kayıt formunu gönderdikten sonra oturum açmışsınızdır.
E-posta hesabınızı kontrol edin ve e-postanızı onaylamak için bağlantıya tıklayın.
Oturum açmadan önce e-posta onayı gerektir
Şu anda bir kullanıcı kayıt formunu tamamladıktan sonra oturum açar. Oturum açmadan önce genellikle e-postalarını onaylamak istersiniz. Aşağıdaki bölümde kodu, yeni kullanıcıların oturum açmadan önce onaylanan bir e-postaya sahip olmasını gerektirecek şekilde değiştireceğiz (kimliği doğrulandı). HttpPost Register
yöntemini aşağıdaki vurgulanmış değişikliklerle güncelleştirin:
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Comment the following line to prevent log in until the user is confirmed.
// await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account",
new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Confirm your account",
"Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");
// Uncomment to debug locally
// TempData["ViewBagLink"] = callbackUrl;
ViewBag.Message = "Check your email and confirm your account, you must be confirmed "
+ "before you can log in.";
return View("Info");
//return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Yöntemi açıklama satırı SignInAsync
yaparak, kullanıcı kayıt tarafından oturum açmaz. Satır, TempData["ViewBagLink"] = callbackUrl;
uygulamada hata ayıklamak ve e-posta göndermeden kaydı test etmek için kullanılabilir. ViewBag.Message
onay yönergelerini görüntülemek için kullanılır. İndirme örneği , e-postayı ayarlamadan e-posta onayını test etmek için kod içerir ve uygulamada hata ayıklamak için de kullanılabilir.
Bir Views\Shared\Info.cshtml
dosya oluşturun ve aşağıdaki razor işaretlemesini ekleyin:
@{
ViewBag.Title = "Info";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
Authorize özniteliğini Giriş denetleyicisinin Contact
eylem yöntemine ekleyin. Anonim kullanıcıların erişimi olmadığını ve kimliği doğrulanmış kullanıcıların erişimi olduğunu doğrulamak için Kişi bağlantısına tıklayabilirsiniz.
[Authorize]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
Eylem yöntemini de güncelleştirmeniz HttpPost Login
gerekir:
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Require the user to have a confirmed email before they can log on.
var user = await UserManager.FindByNameAsync(model.Email);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
ViewBag.errorMessage = "You must have a confirmed email to log on.";
return View("Error");
}
}
// 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:
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);
}
}
Views\Shared\Error.cshtml görünümünü güncelleştirerek hata iletisini görüntüleyin:
@model System.Web.Mvc.HandleErrorInfo
@{
ViewBag.Title = "Error";
}
<h1 class="text-danger">Error.</h1>
@{
if (String.IsNullOrEmpty(ViewBag.errorMessage))
{
<h2 class="text-danger">An error occurred while processing your request.</h2>
}
else
{
<h2 class="text-danger">@ViewBag.errorMessage</h2>
}
}
AspNetUsers tablosunda test etmek istediğiniz e-posta diğer adını içeren tüm hesapları silin. Uygulamayı çalıştırın ve e-posta adresinizi onaylayana kadar oturum açamazsınız. E-posta adresinizi onayladıktan sonra Kişi bağlantısına tıklayın.
Parola kurtarma/sıfırlama
Hesap denetleyicisindeki HttpPost ForgotPassword
eylem yönteminden açıklama karakterlerini kaldırın:
//
// POST: /Account/ForgotPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>");
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
// If we got this far, something failed, redisplay form
return View(model);
}
Views\Account\Login.cshtml razor görünüm dosyasındaki ActionLink'ten ForgotPassword
açıklama karakterlerini kaldırın:
@using MvcPWy.Models
@model LoginViewModel
@{
ViewBag.Title = "Log in";
}
<h2>@ViewBag.Title.</h2>
<div class="row">
<div class="col-md-8">
<section id="loginForm">
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<h4>Use a local account to log in.</h4>
<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.Password, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
@Html.CheckBoxFor(m => m.RememberMe)
@Html.LabelFor(m => m.RememberMe)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Log in" class="btn btn-default" />
</div>
</div>
<p>
@Html.ActionLink("Register as a new user", "Register")
</p>
@* Enable this once you have account confirmation enabled for password reset functionality *@
<p>
@Html.ActionLink("Forgot your password?", "ForgotPassword")
</p>
}
</section>
</div>
<div class="col-md-4">
<section id="socialLoginForm">
@Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { ReturnUrl = ViewBag.ReturnUrl })
</section>
</div>
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Oturum aç sayfasında artık parolayı sıfırlamak için bir bağlantı gösterilir.
E-posta onay bağlantısını yeniden gönder
Kullanıcı yeni bir yerel hesap oluşturduğunda, oturum açabilmesi için önce kullanması gereken bir onay bağlantısı e-postayla gönderilir. Kullanıcı yanlışlıkla onay e-postasını silerse veya e-posta hiç gelmezse, onay bağlantısının yeniden gönderilmesi gerekir. Aşağıdaki kod değişiklikleri bunun nasıl etkinleştirileceği gösterilmektedir.
Controllers\AccountController.cs dosyasının altına aşağıdaki yardımcı yöntemi ekleyin:
private async Task<string> SendEmailConfirmationTokenAsync(string userID, string subject)
{
string code = await UserManager.GenerateEmailConfirmationTokenAsync(userID);
var callbackUrl = Url.Action("ConfirmEmail", "Account",
new { userId = userID, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(userID, subject,
"Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");
return callbackUrl;
}
Register yöntemini yeni yardımcıyı kullanacak şekilde güncelleştirin:
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Comment the following line to prevent log in until the user is confirmed.
// await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account");
ViewBag.Message = "Check your email and confirm your account, you must be confirmed "
+ "before you can log in.";
return View("Info");
//return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Kullanıcı hesabı onaylanmamışsa parolayı yeniden göndermek için Login yöntemini güncelleştirin:
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Require the user to have a confirmed email before they can log on.
// var user = await UserManager.FindByNameAsync(model.Email);
var user = UserManager.Find(model.Email, model.Password);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account-Resend");
// Uncomment to debug locally
// ViewBag.Link = callbackUrl;
ViewBag.errorMessage = "You must have a confirmed email to log on. "
+ "The confirmation token has been resent to your email account.";
return View("Error");
}
}
// 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:
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);
}
}
Sosyal ve yerel oturum açma hesaplarını birleştirme
E-posta bağlantınıza tıklayarak yerel ve sosyal hesapları birleştirebilirsiniz. Aşağıdaki sırayla RickAndMSFT@gmail.com ilk olarak yerel oturum açma olarak oluşturulur, ancak hesabı önce sosyal oturum açma günlüğü olarak oluşturabilir, ardından yerel oturum açma bilgileri ekleyebilirsiniz.
Yönet bağlantısına tıklayın. Bu hesapla ilişkili Dış Oturum Açma Bilgileri: 0'a dikkat edin.
Başka bir oturum açma hizmetinin bağlantısına tıklayın ve uygulama isteklerini kabul edin. İki hesap birleştirildi, iki hesapla da oturum açabileceksiniz. Kullanıcılarınızın kimlik doğrulama hizmetindeki sosyal günlüklerinin kapanması veya sosyal hesaplarına erişimi kaybetme olasılığı daha yüksek olması durumunda yerel hesaplar eklemesini isteyebilirsiniz.
Aşağıdaki görüntüde, Tom bir sosyal oturum açma işlemidir ( dış oturum açma bilgileri: 1 sayfada gösterilmiştir).
Parola seç'e tıklanması, aynı hesapla ilişkili yerel bir oturum açma eklemenize olanak tanır.
E-posta onayı daha ayrıntılı
öğreticim Hesap Onayı ve ASP.NET Kimliği ile Parola Kurtarma bu konuya daha fazla ayrıntıyla giriyor.
Uygulamada hata ayıklama
Bağlantıyı içeren bir e-posta almazsan:
- Gereksiz veya istenmeyen posta klasörünüzü denetleyin.
- SendGrid hesabınızda oturum açın ve E-posta Etkinliği bağlantısına tıklayın.
Doğrulama bağlantısını e-posta olmadan test etmek için tamamlanmış örneği indirin. Onay bağlantısı ve onay kodları sayfada görüntülenir.
Ek Kaynaklar
- ASP.NET Kimliği Önerilen Kaynaklara Bağlantılar
- ASP.NET Kimliği ile Hesap Onayı ve Parola Kurtarma, parola kurtarma ve hesap onayı hakkında daha fazla ayrıntıya gider.
- Facebook, Twitter, LinkedIn ve Google OAuth2 ile MVC 5 Uygulaması Oturum Açma Bu öğreticide , Facebook ve Google OAuth 2 yetkilendirmesine sahip bir ASP.NET MVC 5 uygulaması yazma işlemi gösterilmektedir. Ayrıca, Kimlik veritabanına nasıl ek veri ekleneceğini de gösterir.
- Üyelik, OAuth ve SQL Veritabanı ile Azure'a Güvenli ASP.NET MVC uygulaması dağıtın. Bu öğreticide Azure dağıtımı, rollerle uygulamanızın güvenliğini sağlama, kullanıcı ve rol eklemek için üyelik API'sini kullanma ve ek güvenlik özellikleri eklenmiştir.
- OAuth 2 için google uygulaması oluşturma ve uygulamayı projeye bağlama
- Uygulamayı Facebook'ta oluşturma ve projeye bağlama
- Projede SSL'yi ayarlama