Créer une application web ASP.NET MVC 5 sécurisée avec connexion, confirmation par e-mail et réinitialisation du mot de passe (C#)
par Rick Anderson
Ce tutoriel vous montre comment créer une application web ASP.NET MVC 5 avec confirmation par e-mail et réinitialisation de mot de passe à l’aide du système d’appartenance ASP.NET Identity.
Pour obtenir une version mise à jour de ce didacticiel qui utilise .NET Core, consultez Confirmation de compte et récupération de mot de passe dans ASP.NET Core.
Créer une application MVC ASP.NET
Commencez par installer et exécuter Visual Studio Express 2013 pour le web ou Visual Studio 2013. Installez Visual Studio 2013 Update 3 ou version ultérieure.
Notes
Avertissement : Vous devez installer Visual Studio 2013 Update 3 ou version ultérieure pour suivre ce didacticiel.
Créez un projet web ASP.NET et sélectionnez le modèle MVC. Web Forms prend également en charge ASP.NET Identity. Vous pouvez donc suivre des étapes similaires dans une application de formulaires web.
Laissez l’authentification par défaut comptes d’utilisateur individuels. Si vous souhaitez héberger l’application dans Azure, laissez la case case activée cochée. Plus loin dans le tutoriel, nous allons déployer sur Azure. Vous pouvez ouvrir un compte Azure gratuitement.
Définissez le projet pour utiliser SSL.
Exécutez l’application, cliquez sur le lien Inscrire et inscrivez un utilisateur. À ce stade, la seule validation sur l’e-mail est avec l’attribut [EmailAddress].
Dans Server Explorer, accédez à Data Connections\DefaultConnection\Tables\AspNetUsers, cliquez avec le bouton droit et sélectionnez Ouvrir la définition de table.
L’image suivante montre le
AspNetUsers
schéma :Cliquez avec le bouton droit sur la table AspNetUsers et sélectionnez Afficher les données de table.
À ce stade, l’e-mail n’a pas été confirmé.Cliquez sur la ligne et sélectionnez Supprimer. Vous allez ajouter à nouveau cet e-mail à l’étape suivante, puis envoyer un e-mail de confirmation.
confirmation Email
Il est recommandé de confirmer l’e-mail d’une nouvelle inscription d’utilisateur pour vérifier qu’il n’emprunte pas l’identité de quelqu’un d’autre (autrement dit, il ne s’est pas inscrit auprès de l’e-mail d’une autre personne). Supposons que vous disposiez d’un forum de discussion, vous souhaitez empêcher "bob@example.com"
l’inscription en tant que "joe@contoso.com"
. Sans confirmation par e-mail, "joe@contoso.com"
peut recevoir des e-mails indésirables de votre application. Supposons que Bob s’est inscrit accidentellement en tant que "bib@example.com"
et qu’il ne l’ait pas remarqué, il ne serait pas en mesure d’utiliser la récupération de mot de passe, car l’application n’a pas son adresse e-mail correcte. Email confirmation fournit uniquement une protection limitée contre les bots et ne fournit pas de protection contre les spammeurs déterminés, ils ont de nombreux alias de messagerie de travail qu’ils peuvent utiliser pour s’inscrire.
Vous souhaitez généralement empêcher les nouveaux utilisateurs de publier des données sur votre site web avant qu’elles n’aient été confirmées par e-mail, sms ou autre mécanisme. Dans les sections ci-dessous, nous allons activer la confirmation par e-mail et modifier le code pour empêcher les utilisateurs nouvellement inscrits de se connecter tant que leur e-mail n’a pas été confirmé.
Raccorder SendGrid
Les instructions de cette section ne sont pas à jour. Pour obtenir des instructions mises à jour, consultez Configurer le fournisseur de messagerie SendGrid .
Bien que ce tutoriel montre uniquement comment ajouter une notification par e-mail via SendGrid, vous pouvez envoyer des e-mails à l’aide de SMTP et d’autres mécanismes (voir ressources supplémentaires).
Dans la Console du gestionnaire de package, entrez la commande suivante :
Install-Package SendGrid
Accédez à la page d’inscription à Azure SendGrid et inscrivez-vous pour obtenir un compte SendGrid gratuit. Configurez SendGrid en ajoutant du code similaire à ce qui suit dans 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); } } }
Vous devez ajouter les éléments suivants :
using SendGrid;
using System.Net;
using System.Configuration;
using System.Diagnostics;
Pour simplifier cet exemple, nous allons stocker les paramètres de l’application dans le fichier web.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>
Avertissement
Sécurité : ne stockez jamais de données sensibles dans votre code source. Le compte et les informations d’identification sont stockés dans appSetting. Sur Azure, vous pouvez stocker ces valeurs en toute sécurité sous l’onglet Configurer dans le Portail Azure. Consultez Meilleures pratiques pour le déploiement de mots de passe et d’autres données sensibles sur ASP.NET et Azure.
Activer la confirmation par e-mail dans le contrôleur de compte
//
// 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);
}
Vérifiez que le fichier Views\Account\ConfirmEmail.cshtml a la syntaxe razor correcte. ( Le caractère @ de la première ligne est peut-être manquant. )
@{
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>
Exécutez l’application et cliquez sur le lien Inscrire. Une fois que vous avez envoyé le formulaire d’inscription, vous êtes connecté.
Vérifiez votre compte de messagerie et cliquez sur le lien pour confirmer votre e-mail.
Exiger une confirmation par e-mail avant de vous connecter
Actuellement, une fois qu’un utilisateur a complété le formulaire d’inscription, il est connecté. Vous souhaitez généralement confirmer leur e-mail avant de les connecter. Dans la section ci-dessous, nous allons modifier le code pour exiger que les nouveaux utilisateurs aient un e-mail confirmé avant qu’ils soient connectés (authentifiés). Mettez à jour la HttpPost Register
méthode avec les modifications en surbrillance suivantes :
//
// 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);
}
En commentant la SignInAsync
méthode, l’utilisateur n’est pas connecté par l’inscription. La TempData["ViewBagLink"] = callbackUrl;
ligne peut être utilisée pour déboguer l’application et tester l’inscription sans envoyer d’e-mail. ViewBag.Message
est utilisé pour afficher les instructions de confirmation. L’exemple de téléchargement contient du code pour tester la confirmation par e-mail sans configurer la messagerie, et peut également être utilisé pour déboguer l’application.
Créez un Views\Shared\Info.cshtml
fichier et ajoutez le balisage razor suivant :
@{
ViewBag.Title = "Info";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
Ajoutez l’attribut Authorize à la Contact
méthode d’action du contrôleur Home. Vous pouvez cliquer sur le lien Contact pour vérifier que les utilisateurs anonymes n’ont pas accès et que les utilisateurs authentifiés y ont accès.
[Authorize]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
Vous devez également mettre à jour la méthode d’action HttpPost Login
:
//
// 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);
}
}
Mettez à jour la vue Views\Shared\Error.cshtml pour afficher le message d’erreur :
@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>
}
}
Supprimez tous les comptes de la table AspNetUsers qui contiennent l’alias de messagerie que vous souhaitez tester. Exécutez l’application et vérifiez que vous ne pouvez pas vous connecter tant que vous n’avez pas confirmé votre adresse e-mail. Une fois que vous avez confirmé votre adresse e-mail, cliquez sur le lien Contact .
Récupération/réinitialisation du mot de passe
Supprimez les caractères de commentaire de la HttpPost ForgotPassword
méthode d’action dans le contrôleur de compte :
//
// 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);
}
Supprimez les caractères de commentaire de l’ActionLinkForgotPassword
dans le fichier de vue Razor 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")
}
La page Se connecter affiche maintenant un lien permettant de réinitialiser le mot de passe.
Renvoyer le lien de confirmation de l’e-mail
Une fois qu’un utilisateur a créé un compte local, un lien de confirmation lui est envoyé par e-mail avant de pouvoir se connecter. Si l’utilisateur supprime accidentellement l’e-mail de confirmation, ou si l’e-mail n’arrive jamais, il aura besoin du lien de confirmation envoyé à nouveau. Les modifications de code suivantes montrent comment l’activer.
Ajoutez la méthode d’assistance suivante au bas du fichier Controllers\AccountController.cs :
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;
}
Mettez à jour la méthode Register pour utiliser la nouvelle assistance :
//
// 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);
}
Mettez à jour la méthode Login pour renvoyer le mot de passe si le compte d’utilisateur n’a pas été confirmé :
//
// 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);
}
}
Combiner des comptes de connexion sociaux et locaux
Vous pouvez combiner des comptes locaux et sociaux en cliquant sur votre lien d’e-mail. Dans la séquence RickAndMSFT@gmail.com suivante est d’abord créé en tant que connexion locale, mais vous pouvez d’abord créer le compte en tant que connexion sociale, puis ajouter une connexion locale.
Cliquez sur le lien Gérer . Notez les connexions externes : 0 associées à ce compte.
Cliquez sur le lien vers un autre service de connexion et acceptez les demandes d’application. Les deux comptes ont été combinés. Vous pourrez vous connecter à l’un ou l’autre des comptes. Vous pouvez souhaiter que vos utilisateurs ajoutent des comptes locaux au cas où leur connexion sociale dans le service d’authentification est en panne, ou plus probablement qu’ils ont perdu l’accès à leur compte social.
Dans l’image suivante, Tom est un journal social (que vous pouvez voir dans la page Connexions externes : 1 ).
Cliquer sur Choisir un mot de passe vous permet d’ajouter un journal local associé au même compte.
Email confirmation plus approfondie
Mon tutoriel Confirmation de compte et récupération de mot de passe avec ASP.NET Identity aborde cette rubrique avec plus de détails.
Débogage de l’application
Si vous ne recevez pas d’e-mail contenant le lien :
- Vérifiez votre dossier de courrier indésirable ou de courrier indésirable.
- Connectez-vous à votre compte SendGrid et cliquez sur le lien activité Email.
Pour tester le lien de vérification sans e-mail, téléchargez l’exemple terminé. Le lien de confirmation et les codes de confirmation s’affichent sur la page.
Ressources supplémentaires
- Liens vers les ressources recommandées ASP.NET Identity
- Confirmation de compte et récupération de mot de passe avec ASP.NET Identity Décrit plus en détail la récupération de mot de passe et la confirmation du compte.
- Application MVC 5 avec Facebook, Twitter, LinkedIn et Google OAuth2 Sign-on Ce tutoriel vous montre comment écrire une application MVC 5 ASP.NET avec l’autorisation Facebook et Google OAuth 2. Il montre également comment ajouter des données supplémentaires à la base de données Identity.
- Déployez une application MVC ASP.NET sécurisée avec appartenance, OAuth et SQL Database sur Azure. Ce tutoriel ajoute un déploiement Azure, comment sécuriser votre application avec des rôles, comment utiliser l’API d’appartenance pour ajouter des utilisateurs et des rôles, ainsi que des fonctionnalités de sécurité supplémentaires.
- Création d’une application Google pour OAuth 2 et connexion de l’application au projet
- Création de l’application dans Facebook et connexion de l’application au projet
- Configuration de SSL dans le projet
Commentaires
https://aka.ms/ContentUserFeedback.
Bientôt disponible : Tout au long de 2024, nous allons supprimer progressivement GitHub Issues comme mécanisme de commentaires pour le contenu et le remplacer par un nouveau système de commentaires. Pour plus d’informations, consultezEnvoyer et afficher des commentaires pour