Übung: Anpassen der Identität
In der vorherigen Lerneinheit haben Sie gelernt, wie Anpassungen in ASP.NET Core Identity funktionieren. In dieser Einheit erweitern Sie das Identity-Datenmodell und nehmen die entsprechenden Änderungen der Benutzeroberfläche vor.
Anpassen der Benutzeroberfläche des Benutzerkontos
In diesem Abschnitt erstellen Sie die UI-Dateien für Identity, die anstelle der standardmäßigen Razor-Klassenbibliothek verwendet werden sollen, und passen diese entsprechend an.
Fügen Sie die anzupassenden Benutzerregistrierungsdateien zum Projekt hinzu:
dotnet aspnet-codegenerator identity --dbContext RazorPagesPizzaAuth --files "Account.Manage.EnableAuthenticator;Account.Manage.Index;Account.Register;Account.ConfirmEmail"
Im obigen Befehl:
- informiert die
--dbContext
-Option das Tool über die vorhandene abgeleiteteDbContext
-Klasse namensRazorPagesPizzaAuth
. - legt die
--files
-Option eine durch Semikolons getrennte Liste eindeutiger Dateien fest, die zum Bereich Identity hinzugefügt werden sollen.Account.Manage.Index
ist die Profilverwaltungsseite. Diese Seite wird später in dieser Einheit geändert.Account.Register
ist die Benutzerregistrierungsseite. Diese Seite wird auch in dieser Einheit geändert.Account.Manage.EnableAuthenticator
undAccount.ConfirmEmail
werden in dieser Einheit skizziert, aber nicht geändert.
Tipp
Führen Sie den folgenden Befehl im Stammverzeichnis des Projekts aus, um gültige Werte für die
--files
-Option anzuzeigen:dotnet aspnet-codegenerator identity --listFiles
Die folgenden Dateien werden zum Verzeichnis Areas/Identity hinzugefügt:
- Pages/
- _ViewImports.cshtml
- Account/
- _ViewImports.cshtml
- ConfirmEmail.cshtml
- ConfirmEmail.cshtml.cs
- Register.cshtml
- Register.cshtml.cs
- Manage/
- _ManageNav.cshtml
- _ViewImports.cshtml
- EnableAuthenticator.cshtml
- EnableAuthenticator.cshtml.cs
- Index.cshtml
- Index.cshtml.cs
- ManageNavPages.cs
- informiert die
IdentityUser
erweitern
Sie erhalten eine neue Anforderung, die Namen Ihrer Benutzer zu speichern. Da die Standardklasse IdentityUser
keine Eigenschaften für Vor- und Nachnamen enthält, müssen Sie die Klasse RazorPagesPizzaUser
erweitern.
Nehmen Sie an Areas/Identity/Data/RazorPagesPizzaUser.cs die folgenden Änderungen vor:
Fügen Sie die Eigenschaften
FirstName
undLastName
hinzu:using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Identity; namespace RazorPagesPizza.Areas.Identity.Data; public class RazorPagesPizzaUser : IdentityUser { [Required] [MaxLength(100)] public string FirstName { get; set; } = string.Empty; [Required] [MaxLength(100)] public string LastName { get; set; } = string.Empty; }
Die Eigenschaften im vorherigen Codeausschnitt stellen weitere Spalten dar, die in der zugrunde liegenden
AspNetUsers
-Tabelle erstellt werden. Beide Eigenschaften sind erforderlich und werden daher mit dem[Required]
-Attribut versehen. Darüber hinaus gibt das[MaxLength]
-Attribut eine zulässige maximale Länge von 100 Zeichen an. Der Datentyp der zugrunde liegenden Tabellenspalte wird entsprechend definiert. Der Standardwertstring.Empty
wird zugewiesen, weil der Nullwerte zulassende Kontext in diesem Projekt aktiviert ist und die Eigenschaften nicht nullbare Zeichenfolgen sind.Fügen Sie am Anfang der Datei die folgende
using
-Anweisung hinzu.using System.ComponentModel.DataAnnotations;
Der obige Code löst die Datenanmerkungsattribute auf, die auf die Eigenschaften
FirstName
undLastName
angewendet werden.
Aktualisieren der Datenbank
Nachdem die Modelländerungen nun vorgenommen wurden, müssen entsprechende Änderungen an der Datenbank vorgenommen werden.
Vergewissern Sie sich, dass alle Ihre Änderungen gespeichert werden.
Erstellen Sie eine EF Core-Migration, und wenden Sie sie an, um den zugrunde liegenden Datenspeicher zu aktualisieren:
dotnet ef migrations add UpdateUser dotnet ef database update
Die EF Core-Migration
UpdateUser
wendet ein DDL-Änderungsskript auf das Schema derAspNetUsers
-Tabelle an. Wie in der folgenden Migrationsausgabe zu sehen ist, wurden die SpaltenFirstName
undLastName
hinzugefügt:info: Microsoft.EntityFrameworkCore.Database.Command[20101] Executed DbCommand (37ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] ALTER TABLE [AspNetUsers] ADD [FirstName] nvarchar(100) NOT NULL DEFAULT N''; info: Microsoft.EntityFrameworkCore.Database.Command[20101] Executed DbCommand (36ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] ALTER TABLE [AspNetUsers] ADD [LastName] nvarchar(100) NOT NULL DEFAULT N'';
Untersuchen Sie die Datenbank, um die Auswirkungen der EF Core-Migration
UpdateUser
auf das Schema derAspNetUsers
-Tabelle zu analysieren.Erweitern Sie im Bereich SQL Server den Knoten Spalten für die dbo.AspNetUsers-Tabelle.
Die Eigenschaften
FirstName
undLastName
in der KlasseRazorPagesPizzaUser
entsprechen den SpaltenFirstName
undLastName
in der obigen Abbildung. Beiden Spalten wurde aufgrund der[MaxLength(100)]
-Attribute der Datentypnvarchar(100)
zugewiesen. Die Nicht-NULL-Einschränkung wurde hinzugefügt, daFirstName
undLastName
in der Klasse nicht nullbare Zeichenfolgen sind. Vorhandene Zeilen zeigen in den neuen Spalten leere Zeichenfolgen an.
Anpassen des Benutzerregistrierungsformulars
Sie haben neue Spalten für FirstName
und LastName
hinzugefügt. Jetzt müssen Sie die Benutzeroberfläche bearbeiten, um die entsprechenden Felder im Registrierungsformular anzuzeigen.
Fügen Sie das folgende hervorgehobene Markup in Areas/Identity/Pages/Account/Register.cshtml ein:
<form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post"> <h2>Create a new account.</h2> <hr /> <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div> <div class="form-floating mb-3"> <input asp-for="Input.FirstName" class="form-control" /> <label asp-for="Input.FirstName"></label> <span asp-validation-for="Input.FirstName" class="text-danger"></span> </div> <div class="form-floating mb-3"> <input asp-for="Input.LastName" class="form-control" /> <label asp-for="Input.LastName"></label> <span asp-validation-for="Input.LastName" class="text-danger"></span> </div> <div class="form-floating mb-3"> <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" /> <label asp-for="Input.Email">Email</label> <span asp-validation-for="Input.Email" class="text-danger"></span> </div>
Mit dem obigen Markup werden die Textfelder First name und Last name (Vorname und Nachname) zum Benutzerregistrierungsformular hinzugefügt.
Fügen Sie in Areas/Identity/Pages/Account/Register.cshtml.cs Unterstützung für die Namenstextfelder ein.
Fügen Sie die Eigenschaften
FirstName
undLastName
zur geschachtelten KlasseInputModel
hinzu:public class InputModel { [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 1)] [Display(Name = "First name")] public string FirstName { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 1)] [Display(Name = "Last name")] public string LastName { get; set; } /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; }
Die
[Display]
-Attribute definieren den Bezeichnungstext, der den Textfeldern zugeordnet werden soll.Ändern Sie die
OnPostAsync
-Methode, um die EigenschaftenFirstName
undLastName
für dasRazorPagesPizza
-Objekt festzulegen. Fügen Sie die folgenden hervorgehobenen Zeilen hinzu:public async Task<IActionResult> OnPostAsync(string returnUrl = null) { returnUrl ??= Url.Content("~/"); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); if (ModelState.IsValid) { var user = CreateUser(); user.FirstName = Input.FirstName; user.LastName = Input.LastName; await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); var result = await _userManager.CreateAsync(user, Input.Password);
Durch diese Änderung wird für die Eigenschaften
FirstName
undLastName
die Benutzereingabe aus dem Registrierungsformular festgelegt.
Anpassen des Websiteheaders
Ändern Sie Pages/Shared/_LoginPartial.cshtml, um die während der Benutzerregistrierung erfassten Vor- und Nachnamen anzuzeigen. Sie benötigen die hervorgehobenen Zeilen aus dem folgenden Codeausschnitt:
<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
RazorPagesPizzaUser? user = await UserManager.GetUserAsync(User);
var fullName = $"{user?.FirstName} {user?.LastName}";
<li class="nav-item">
<a id="manage" class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello, @fullName!</a>
</li>
UserManager.GetUserAsync(User)
gibt ein RazorPagesPizzaUser
Objekt zurück, welches Nullwerte zulässt. Der nullbedingte ?.
-Operator wird nur verwendet, um auf die Eigenschaften FirstName
und LastName
zuzugreifen, wenn das RazorPagesPizzaUser
-Objekt nicht null ist.
Anpassen des Profilverwaltungsformulars
Sie haben die neuen Felder zum Benutzerregistrierungsformular hinzugefügt. Sie sollten sie aber auch dem Profilverwaltungsformular hinzufügen, damit vorhandene Benutzer sie bearbeiten können.
Fügen Sie das folgende hervorgehobene Markup in Areas/Identity/Pages/Account/Manage/Index.cshtml ein: Speichern Sie die Änderungen.
<form id="profile-form" method="post"> <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div> <div class="form-floating mb-3"> <input asp-for="Input.FirstName" class="form-control" /> <label asp-for="Input.FirstName"></label> <span asp-validation-for="Input.FirstName" class="text-danger"></span> </div> <div class="form-floating mb-3"> <input asp-for="Input.LastName" class="form-control" /> <label asp-for="Input.LastName"></label> <span asp-validation-for="Input.LastName" class="text-danger"></span> </div> <div class="form-floating mb-3"> <input asp-for="Username" class="form-control" disabled /> <label asp-for="Username" class="form-label"></label> </div>
Nehmen Sie die folgenden Änderungen in Areas/Identity/Pages/Account/Manage/Index.cshtml.cs vor, um die Namenstextfelder zu unterstützen.
Fügen Sie die Eigenschaften
FirstName
undLastName
zur geschachtelten KlasseInputModel
hinzu:public class InputModel { [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 1)] [Display(Name = "First name")] public string FirstName { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 1)] [Display(Name = "Last name")] public string LastName { get; set; } /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> [Phone] [Display(Name = "Phone number")] public string PhoneNumber { get; set; } }
Fügen Sie die folgenden hervorgehobenen Änderungen in die
LoadAsync
-Methode ein:private async Task LoadAsync(RazorPagesPizzaUser user) { var userName = await _userManager.GetUserNameAsync(user); var phoneNumber = await _userManager.GetPhoneNumberAsync(user); Username = userName; Input = new InputModel { PhoneNumber = phoneNumber, FirstName = user.FirstName, LastName = user.LastName }; }
Der obige Code unterstützt das Abrufen des Vor- und Nachnamen, um diese in den entsprechenden Feldern des Profilverwaltungsformulars anzuzeigen.
Fügen Sie die hervorgehobenen Änderungen in die
OnPostAsync
-Methode ein. Speichern Sie die Änderungen.public async Task<IActionResult> OnPostAsync() { var user = await _userManager.GetUserAsync(User); if (user == null) { return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); } if (!ModelState.IsValid) { await LoadAsync(user); return Page(); } user.FirstName = Input.FirstName; user.LastName = Input.LastName; await _userManager.UpdateAsync(user); var phoneNumber = await _userManager.GetPhoneNumberAsync(user); if (Input.PhoneNumber != phoneNumber) { var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber); if (!setPhoneResult.Succeeded) { StatusMessage = "Unexpected error when trying to set phone number."; return RedirectToPage(); } } await _signInManager.RefreshSignInAsync(user); StatusMessage = "Your profile has been updated"; return RedirectToPage(); }
Der obige Code unterstützt das Aktualisieren des Vor- und Nachnamen im der
AspNetUsers
-Tabelle der Datenbank.
Konfigurieren des Bestätigungs-E-Mail-Absenders
Als Sie die App zum ersten Mal getestet haben, haben Sie einen Benutzer registriert und dann auf einen Link geklickt, um die Bestätigung der E-Mail-Adresse des Benutzers zu simulieren. Um eine echte Bestätigungs-E-Mail zu senden, müssen Sie eine Implementierung von IEmailSender erstellen und im Abhängigkeitsinjektionssystem registrieren. Der Einfachheit halber werden in Ihrer Implementierung in dieser Einheit keine tatsächlichen E-Mails an einen SMTP-Server (Simple Mail Transfer Protocol) gesendet. Der E-Mail-Inhalt wird einfach an der Konsole ausgegeben.
Da Sie die E-Mail in der Konsole als unformatierten Text anzeigen möchten, sollten Sie die generierte Nachricht ändern, um HTML-codierten Text auszuschließen. Suchen Sie in Areas/Identity/Pages/Account/Register.cshtml.cs den folgenden Code:
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
Ändern Sie ihn in:
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", $"Please confirm your account by visiting the following URL:\r\n\r\n{callbackUrl}");
Klicken Sie im Explorer-Bereich mit der rechten Maustaste auf den Ordner RazorPagesPizza\Dienste, und erstellen Sie eine neue Datei namens EmailSender.cs. Öffnen Sie die Datei, und fügen Sie den folgenden Code hinzu:
using Microsoft.AspNetCore.Identity.UI.Services; namespace RazorPagesPizza.Services; public class EmailSender : IEmailSender { public EmailSender() {} public Task SendEmailAsync(string email, string subject, string htmlMessage) { Console.WriteLine(); Console.WriteLine("Email Confirmation Message"); Console.WriteLine("--------------------------"); Console.WriteLine($"TO: {email}"); Console.WriteLine($"SUBJECT: {subject}"); Console.WriteLine($"CONTENTS: {htmlMessage}"); Console.WriteLine(); return Task.CompletedTask; } }
Der obige Code erstellt eine Implementierung von IEmailSender, die den Inhalt der Nachricht in der Konsole ausgibt. In einer realen Implementierung würde
SendEmailAsync
eine Verbindung mit einem externen E-Mail-Dienst herstellen oder eine anderen Aktion zum Senden der E-Mails ausführen.Fügen Sie in Program.cs die hervorgehobenen Zeilen hinzu:
using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using RazorPagesPizza.Areas.Identity.Data; using Microsoft.AspNetCore.Identity.UI.Services; using RazorPagesPizza.Services; var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("RazorPagesPizzaAuthConnection"); builder.Services.AddDbContext<RazorPagesPizzaAuth>(options => options.UseSqlServer(connectionString)); builder.Services.AddDefaultIdentity<RazorPagesPizzaUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<RazorPagesPizzaAuth>(); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddTransient<IEmailSender, EmailSender>(); var app = builder.Build();
Dadurch wird
EmailSender
im Abhängigkeitsinjektionssystem alsIEmailSender
registriert.
Testen der Änderungen am Registrierungsformular
Das ist alles! Lassen Sie uns die Änderungen des Registrierungsformulars und der Bestätigungs-E-Mail testen.
Vergewissern Sie sich, dass Sie alle Änderungen gespeichert haben.
Erstellen Sie im Terminalbereich das Projekt, und führen Sie die App mit
dotnet run
aus.Navigieren Sie im Browser zur App. Wählen Sie Abmelden aus, falls Sie angemeldet sind.
Klicken Sie auf Register (Registrieren), und verwenden Sie das neue Formular, um einen neuen Benutzer zu registrieren.
Hinweis
Die Validierungseinschränkungen für die Felder Vorname und Nachname stellen die Datenanmerkungen der Eigenschaften
FirstName
undLastName
vonInputModel
dar.Nach der Registrierung werden Sie zum Bildschirm Bestätigen der Registrierung umgeleitet. Scrollen Sie im Terminalbereich nach oben, um die folgende Konsolenausgabe zu finden:
Email Confirmation Message -------------------------- TO: jana.heinrich@contoso.com SUBJECT: Confirm your email CONTENTS: Please confirm your account by visiting the following URL: https://localhost:7192/Identity/Account/ConfirmEmail?<query string removed>
Navigieren Sie mit STRG+Klick zur URL. Der Bestätigungsbildschirm wird angezeigt.
Hinweis
Wenn Sie GitHub Codespaces verwenden, müssen Sie möglicherweise
-7192
zum ersten Teil der weitergeleiteten URL hinzufügen. Beispiel:scaling-potato-5gr4j4-7192.preview.app.github.dev
.Wählen Sie Anmelden aus, und melden Sie sich mit dem neuen Benutzer an. Der Header der App enthält nun Hello, [Vorname] [Nachname]!.
Klicken Sie im Bereich SQL Server in VS Code mit der rechten Maustaste auf die Datenbank RazorPagesPizza, und wählen Sie Neue Abfrage aus. Geben Sie in der angezeigten Registerkarte die folgende Abfrage ein, und drücken Sie STRG+UMSCHALTASTE+E,um sie auszuführen.
SELECT UserName, Email, FirstName, LastName FROM dbo.AspNetUsers
Eine Registerkarte mit ähnlichen Ergebnissen wie folgt wird angezeigt:
UserName Email FirstName LastName kai.klein@contoso.com kai.klein@contoso.com jana.heinrich@contoso.com jana.heinrich@contoso.com Jana Heinrich Der erste Benutzer hat sich registriert, bevor
FirstName
undLastName
zum Schema hinzugefügt wurden. Daher enthält der zugehörige TabelleneintragAspNetUsers
in diesen Spalten keine Daten.
Testen der Änderungen am Profilverwaltungsformular
Sie sollten auch die Änderungen testen, die Sie am Profilverwaltungsformular vorgenommen haben.
Melden Sie sich mit dem zuerst erstellten Benutzerkonto bei der Web-App an.
Klicken Sie auf den Link Hallo,, um das Profilverwaltungsformular aufzurufen.
Hinweis
Der Link wird nicht ordnungsgemäß angezeigt, weil die
AspNetUsers
-Zeile der Tabelle für diesen Benutzer keine Werte fürFirstName
undLastName
enthält.Geben Sie gültige Werte für Vorname und Nachname ein. Klicken Sie auf Speichern.
Der Header der App wird in Hello, [Vorname] [Nachname]! geändert.
Um die App zu beenden, drücken Sie im Terminalbereich in VS Code STRG+C.
Zusammenfassung
In dieser Einheit haben Sie Identity angepasst, um benutzerdefinierte Benutzerinformationen zu speichern. Sie haben außerdem die Bestätigungs-E-Mail angepasst. In der nächsten Lerneinheit erfahren Sie mehr über die Implementierung der Multi-Faktor-Authentifizierung in Identity.