Vytvoření zabezpečené webové aplikace ASP.NET MVC 5 s přihlášením, potvrzením e-mailu a resetováním hesla (C#)
V tomto kurzu se dozvíte, jak vytvořit webovou aplikaci ASP.NET MVC 5 s potvrzením e-mailu a resetováním hesla pomocí systému členství ASP.NET Identity.
Aktualizovanou verzi tohoto kurzu, která používá .NET Core, najdete v tématu Potvrzení účtu a obnovení hesla v ASP.NET Core.
Vytvoření aplikace ASP.NET MVC
Začněte instalací a spuštěním Visual Studio Express 2013 pro web nebo Visual Studio 2013. Nainstalujte Visual Studio 2013 Update 3 nebo novější.
Poznámka
Upozornění: K dokončení tohoto kurzu musíte nainstalovat aktualizaci Visual Studio 2013 Update 3 nebo vyšší.
Vytvořte nový webový projekt ASP.NET a vyberte šablonu MVC. Web Forms také podporuje ASP.NET Identity, takže v aplikaci webových formulářů můžete postupovat podobně.
Výchozí ověřování ponechte na individuálních uživatelských účtech. Pokud chcete aplikaci hostovat v Azure, nechte políčko zaškrtnuté. Později v tomto kurzu nasadíme do Azure. Účet Azure si můžete otevřít zdarma.
Nastavte projekt tak, aby používal SSL.
Spusťte aplikaci, klikněte na odkaz Zaregistrovat a zaregistrujte uživatele. V tomto okamžiku je jediným ověřením e-mailu atribut [EmailAddress].
V Průzkumníku serveru přejděte na Data Connections\DefaultConnection\Tables\AspNetUsers, klikněte pravým tlačítkem a vyberte Otevřít definici tabulky.
Následující obrázek znázorňuje
AspNetUsers
schéma:Klikněte pravým tlačítkem na tabulku AspNetUsers a vyberte Zobrazit data tabulky.
V tomto okamžiku nebyl e-mail potvrzen.Klikněte na řádek a vyberte Odstranit. Tento e-mail znovu přidáte v dalším kroku a odešlete potvrzovací e-mail.
potvrzení Email
Osvědčeným postupem je potvrdit e-mail s registrací nového uživatele, abyste ověřili, že se nezasadí za někoho jiného (to znamená, že se nezaregistroval v e-mailu někoho jiného). Předpokládejme, že jste měli diskuzní fórum, chcete zabránit "bob@example.com"
registraci jako "joe@contoso.com"
. Bez potvrzení "joe@contoso.com"
e-mailu můžete z vaší aplikace dostávat nežádoucí e-maily. Předpokládejme, že se Bob omylem zaregistroval jako "bib@example.com"
a nevšiml si toho, že by nemohl použít obnovení hesla, protože aplikace nemá jeho správný e-mail. Email potvrzení poskytuje pouze omezenou ochranu před roboty a neposkytuje ochranu před určenými spammery, mají mnoho pracovních e-mailových aliasů, které můžou použít k registraci.
Obecně chcete zabránit novým uživatelům v publikování jakýchkoli dat na váš web předtím, než je potvrdíte e-mailem, sms zprávou nebo jiným mechanismem. V následujících částech povolíme e-mailové potvrzení a upravíme kód, aby se nově zaregistrovaní uživatelé nemohli přihlásit, dokud se jejich e-mail nepotvrdí.
Připojit SendGrid
Pokyny v této části nejsou aktuální. Aktualizované pokyny najdete v tématu Konfigurace poskytovatele e-mailu SendGrid .
I když tento kurz ukazuje, jak přidat e-mailové oznámení prostřednictvím SendGrid, můžete posílat e-maily pomocí smtp a dalších mechanismů (viz další zdroje informací).
V konzole Správce balíčků zadejte následující příkaz:
Install-Package SendGrid
Přejděte na registrační stránku Azure SendGrid a zaregistrujte si bezplatný účet SendGrid. Nakonfigurujte SendGrid přidáním kódu podobného následujícímu v App_Start/IdentityConfig.cs:
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); } } }
Budete muset přidat následující položky:
using SendGrid;
using System.Net;
using System.Configuration;
using System.Diagnostics;
Aby byla tato ukázka jednoduchá, uložíme nastavení aplikace do souboruweb.config :
</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>
Upozornění
Zabezpečení – nikdy neukládejte citlivá data ve zdrojovém kódu. Účet a přihlašovací údaje jsou uložené v nastavení aplikace. V Azure můžete tyto hodnoty bezpečně uložit na kartě Konfigurace v Azure Portal. Viz Osvědčené postupy pro nasazení hesel a dalších citlivých dat do ASP.NET a Azure.
Povolení e-mailového potvrzení v kontroleru účtů
//
// 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);
}
Ověřte, že soubor Views\Account\ConfirmEmail.cshtml má správnou syntaxi razor. ( Znak @ v prvním řádku může chybět. )
@{
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>
Spusťte aplikaci a klikněte na odkaz Zaregistrovat. Jakmile odešlete registrační formulář, budete přihlášeni.
Zkontrolujte svůj e-mailový účet a kliknutím na odkaz potvrďte svůj e-mail.
Před přihlášením vyžadovat potvrzení e-mailem
V současné době, jakmile uživatel vyplní registrační formulář, je přihlášen. Obvykle chcete před přihlášením potvrdit jeho e-mail. V následující části upravíme kód tak, aby před přihlášením (ověřením) museli mít noví uživatelé potvrzený e-mail. Aktualizujte metodu HttpPost Register
pomocí následujících zvýrazněných změn:
//
// 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);
}
Když metodu SignInAsync
zakomentuje, uživatel se registrací nepřihlásí. Řádek TempData["ViewBagLink"] = callbackUrl;
se dá použít k ladění aplikace a testování registrace bez odeslání e-mailu. ViewBag.Message
slouží k zobrazení pokynů pro potvrzení. Ukázka ke stažení obsahuje kód pro testování potvrzení e-mailu bez nastavení e-mailu a dá se také použít k ladění aplikace.
Vytvořte Views\Shared\Info.cshtml
soubor a přidejte následující kód razor:
@{
ViewBag.Title = "Info";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
Přidejte atribut Authorize do Contact
metody action kontroleru Home. Kliknutím na odkaz Kontakt můžete ověřit, že anonymní uživatelé nemají přístup a ověření uživatelé mají přístup.
[Authorize]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
Musíte také aktualizovat metodu HttpPost Login
akce:
//
// 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);
}
}
Aktualizujte zobrazení Views\Shared\Error.cshtml tak, aby se zobrazila chybová zpráva:
@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>
}
}
Odstraňte všechny účty v tabulce AspNetUsers , které obsahují e-mailový alias, se kterým chcete testovat. Spusťte aplikaci a ověřte, že se nemůžete přihlásit, dokud nepotvrdíte svoji e-mailovou adresu. Po potvrzení e-mailové adresy klikněte na odkaz Kontakt .
Obnovení nebo resetování hesla
Odeberte znaky komentáře z HttpPost ForgotPassword
metody akce v kontroleru účtu:
//
// 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);
}
Odeberte znaky komentáře z ForgotPassword
ActionLink v souboru razor view Views\Account\Login.cshtml :
@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")
}
Na přihlašovací stránce se teď zobrazí odkaz pro resetování hesla.
Znovu odeslat e-mail s potvrzením
Jakmile uživatel vytvoří nový místní účet, dostane e-mailem potvrzovací odkaz, který musí použít, aby se mohl přihlásit. Pokud uživatel omylem odstraní potvrzovací e-mail nebo e-mail nikdy nedorazí, bude muset znovu odeslat potvrzovací odkaz. Následující změny kódu ukazují, jak to povolit.
Do dolní části souboru Controllers\AccountController.cs přidejte následující pomocnou metodu:
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;
}
Aktualizujte metodu Register tak, aby používala novou pomocnou rutinu:
//
// 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);
}
Aktualizujte metodu Login tak, aby znovu odeslala heslo, pokud uživatelský účet nebyl potvrzen:
//
// 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);
}
}
Kombinování sociálních a místních přihlašovacích účtů
Místní účty a účty na sociálních sítích můžete zkombinovat kliknutím na e-mailový odkaz. V následujícím pořadí RickAndMSFT@gmail.com se nejprve vytvoří jako místní přihlášení, ale nejprve můžete vytvořit účet jako přihlášení na sociální sítě a pak přidat místní přihlášení.
Klikněte na odkaz Spravovat . Všimněte si externích přihlášení: 0 přidružených k tomuto účtu.
Klikněte na odkaz na jinou přihlašovací službu a přijměte žádosti aplikace. Oba účty byly sloučeny, budete se moct přihlásit pomocí jednoho z těchto účtů. Můžete chtít, aby vaši uživatelé přidali místní účty v případě, že je jejich služba pro ověřování sociálních sítí mimo provoz nebo je pravděpodobnější, že ztratili přístup ke svému účtu na sociální sítě.
Na následujícím obrázku je Tom sociální přihlášení (které můžete vidět v externích přihlášeních: 1 na stránce).
Kliknutím na Vybrat heslo můžete přidat místní přihlášení přidružené ke stejnému účtu.
Email podrobnější potvrzení
Můj kurz Potvrzení účtu a obnovení hesla pomocí ASP.NET Identity je v tomto tématu s dalšími podrobnostmi.
Ladění aplikace
Pokud nedostanete e-mail obsahující odkaz:
- Zkontrolujte složku s nevyžádanou poštou nebo spamem.
- Přihlaste se ke svému účtu SendGrid a klikněte na odkaz aktivita Email.
Pokud chcete ověřovací odkaz otestovat bez e-mailu, stáhněte si hotovou ukázku. Na stránce se zobrazí potvrzovací odkaz a potvrzovací kódy.
Další materiály
- Odkazy na doporučené zdroje informací o identitě ASP.NET
- Potvrzení účtu a obnovení hesla pomocí identity ASP.NET Podrobnější informace o obnovení hesla a potvrzení účtu.
- Aplikace MVC 5 s přihlášením k Facebooku, Twitteru, LinkedInu a Google OAuth2 V tomto kurzu se dozvíte, jak napsat aplikaci ASP.NET MVC 5 s autorizací Facebook a Google OAuth 2. Ukazuje také, jak přidat další data do databáze identit.
- Nasaďte do Azure aplikaci Secure ASP.NET MVC s členstvím, OAuth a SQL Database. V tomto kurzu se přidá nasazení Azure, postup zabezpečení aplikace pomocí rolí, použití rozhraní API členství k přidání uživatelů a rolí a další funkce zabezpečení.
- Vytvoření aplikace Google pro OAuth 2 a připojení aplikace k projektu
- Vytvoření aplikace na Facebooku a připojení aplikace k projektu
- Nastavení SSL v projektu
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro