Oefening: identiteit aanpassen

Voltooid

In de vorige les hebt u geleerd hoe aanpassing werkt in ASP.NET Core Identity. In deze les breidt u het identiteitsgegevensmodel uit en voert u de bijbehorende wijzigingen in de gebruikersinterface aan.

De gebruikersinterface van het gebruikersaccount aanpassen

In deze sectie gaat u de identiteitsgebruikersinterfacebestanden maken en aanpassen die moeten worden gebruikt in plaats van de standaard Razor-klassebibliotheek.

  1. Voeg de te wijzigen gebruikersregistratiebestanden toe aan het project:

    dotnet aspnet-codegenerator identity --dbContext RazorPagesPizzaAuth --files "Account.Manage.EnableAuthenticator;Account.Manage.Index;Account.Register;Account.ConfirmEmail"
    

    In de voorgaande opdracht:

    • Met de optie --dbContext wordt het hulpprogramma geïnformeerd over de bestaande, van DbContext afgeleide klasse met de naam RazorPagesPizzaAuth.
    • Met de optie --files geeft u een lijst met door puntkomma's gescheiden unieke bestanden op die moeten worden toegevoegd aan het gebied Identiteit.
      • Account.Manage.Index is de profielbeheerpagina. Deze pagina wordt verderop in deze les gewijzigd.
      • Account.Register is de registratiepagina van de gebruiker. Deze pagina wordt ook gewijzigd in deze eenheid.
      • Account.Manage.EnableAuthenticator en Account.ConfirmEmail zijn geveerd, maar niet gewijzigd in deze eenheid.

    Tip

    Voer de volgende opdracht uit vanuit de hoofdmap van het project om geldige waarden voor de --files optie weer te geven: dotnet aspnet-codegenerator identity --listFiles

    De volgende bestanden zijn toegevoegd aan de map Areas/Identity:

    • 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

Verlengen IdentityUser

U krijgt een nieuwe vereiste om de namen van uw gebruikers op te slaan. Omdat de standaardklasse IdentityUser geen eigenschappen voor voor- en achternamen bevat, moet u de RazorPagesPizzaUser klasse uitbreiden.

Breng de volgende wijzigingen aan in Areas/Identity/Data/RazorPagesPizzaUser.cs:

  1. Voeg de eigenschappen FirstName en LastName toe:

    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;
    }
    

    De eigenschappen in het voorgaande fragment vertegenwoordigen extra kolommen die in de onderliggende tabel AspNetUsers moeten worden gemaakt. Beide eigenschappen zijn vereist en hebben daarom het kenmerk [Required] als aantekening gekregen. Daarnaast geeft het kenmerk [MaxLength] aan dat een maximale lengte van 100 tekens is toegestaan. Het gegevenstype van de onderliggende tabelkolom is dienovereenkomstig gedefinieerd. Er wordt een standaardwaarde string.Empty toegewezen omdat nullable context is ingeschakeld in dit project en de eigenschappen niet-nullable tekenreeksen zijn.

  2. Voeg boven in het bestand de volgende using-instructie toe.

    using System.ComponentModel.DataAnnotations;
    

    Met de voorgaande code worden de kenmerken voor gegevensaantekeningen die zijn toegepast op de eigenschappen FirstName en LastName omgezet.

De database bijwerken

Nu de modelwijzigingen zijn aangebracht, moeten de bijbehorende wijzigingen worden aangebracht in de database.

  1. Zorg ervoor dat al uw wijzigingen worden opgeslagen.

  2. Maak een EF Core-migratie en pas deze toe om het onderliggende gegevensarchief bij te werken:

    dotnet ef migrations add UpdateUser
    dotnet ef database update
    

    Voor de UpdateUser-EF Core-migratie is een DDL-wijzigingsscript toegepast op het schema AspNetUsers van de tabel. Om precies te zijn, zijn de kolommen FirstName en LastName toegevoegd, zoals te zien is in het volgende fragment van de migratieuitvoer:

    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'';
    
  3. Bekijk de database om het effect van de UpdateUser EF Core-migratie in het schema van de AspNetUsers tabel te analyseren.

    Vouw in het deelvenster SQL Server het knooppunt Kolommen in de dbo uit. De tabel AspNetUsers .

    Schermopname van het schema van de tabel AspNetUsers.

    De FirstName en LastName eigenschappen in de RazorPagesPizzaUser klasse komen overeen met de FirstName kolommen LastName in de voorgaande afbeelding. Er is een gegevenstype nvarchar(100) toegewezen aan elk van de twee kolommen vanwege de [MaxLength(100)]-kenmerken. De niet-null-beperking is toegevoegd omdat FirstName en LastName in de klasse niet-nullable tekenreeksen zijn. Bestaande rijen bevatten lege tekenreeksen in de nieuwe kolommen.

Het gebruikersregistratieformulier aanpassen

U hebt nieuwe kolommen toegevoegd voor FirstName en LastName. Nu moet u de gebruikersinterface bewerken om overeenkomende velden op het registratieformulier weer te geven.

  1. Voeg in Areas/Identity/Pages/Account/Register.cshtml de volgende gemarkeerde markeringen toe:

    <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>
    

    Met de voorgaande markering worden de tekstvakken Voornaam en Achternaam toegevoegd aan het gebruikersregistratieformulier.

  2. Voeg in Areas/Identity/Pages/Account/Register.cshtml.cs ondersteuning toe voor de naamtekstvakken.

    1. Voeg de eigenschappen FirstName en LastName toe aan de geneste klasse InputModel:

      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; }
      

      Met de [Display]-kenmerken wordt de labeltekst gedefinieerd die aan de tekstvakken moet worden gekoppeld.

    2. Wijzig de methode OnPostAsync om de eigenschappen FirstName en LastName in te stellen voor het object RazorPagesPizza. Voeg de volgende gemarkeerde regels toe:

      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);
      
      

      Met de voorgaande wijziging worden de eigenschappen FirstName en LastName ingesteld voor de gebruikersinvoer van het registratieformulier.

De websiteheader aanpassen

Werk Pages/Shared/_LoginPartial.cshtml bij om de voor- en achternaam weer te geven die tijdens de gebruikersregistratie zijn verzameld. De gemarkeerde regels in het volgende codefragment zijn nodig:

<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) retourneert een null-object RazorPagesPizzaUser . De operator null-voorwaardelijk ?. wordt alleen gebruikt voor toegang tot de FirstName en LastName eigenschappen als het RazorPagesPizzaUser object niet null is.

Het profielbeheerformulier aanpassen

U hebt de nieuwe velden toegevoegd aan het gebruikersregistratieformulier, maar u moet ze ook toevoegen aan het profielbeheerformulier, zodat bestaande gebruikers ze kunnen bewerken.

  1. Voeg in Areas/Identity/Pages/Account/Manage/Index.cshtml de volgende gemarkeerde markeringen toe. Sla uw wijzigingen op.

    <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>
    
  2. Breng in Areas/Identity/Pages/Account/Manage/Index.cshtml.cs de volgende wijzigingen aan om de naamtekstvakken te ondersteunen.

    1. Voeg de eigenschappen FirstName en LastName toe aan de geneste klasse InputModel:

      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; }
      }
      
    2. Neem de gemarkeerde wijzigingen op in de methode LoadAsync:

      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
          };
      }
      

      De voorgaande code biedt ondersteuning voor het ophalen van de voor- en achternaam voor weergave in de overeenkomstige tekstvakken op het profielbeheerformulier.

    3. Neem de gemarkeerde wijzigingen op in de methode OnPostAsync. Sla uw wijzigingen op.

      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();
      }
      

      De voorgaande code ondersteunt het bijwerken van de voor- en achternaam in de tabel AspNetUsers van de database.

De afzender van de bevestigingsmail configureren

De eerste keer dat u de app hebt getest, hebt u een gebruiker geregistreerd en vervolgens op een koppeling geklikt om te simuleren dat het e-mailadres van de gebruiker wordt bevestigd. Als u een bevestigingsmail wilt verzenden, moet u een implementatie maken van IEmailSender en registreren in het systeem voor afhankelijkheidsinjectie. Om het eenvoudig te houden, verzendt uw implementatie in deze les geen e-mail naar een SMTP-server (Simple Mail Transfer Protocol). Hiermee wordt alleen de e-mailinhoud naar de console geschreven.

  1. Omdat u het e-mailbericht in tekst zonder opmaak in de console wilt weergeven, moet u het gegenereerde bericht wijzigen om html-gecodeerde tekst uit te sluiten. Zoek in gebieden/identiteit/pagina's/account/Register.cshtml.cs de volgende code:

    await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
        $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
    

    Wijzig dit in:

    await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
        $"Please confirm your account by visiting the following URL:\r\n\r\n{callbackUrl}");
    
  2. Klik in het deelvenster Explorer met de rechtermuisknop op de map RazorPagesPizza\Services en maak een nieuw bestand met de naam EmailSender.cs. Open bestand en voeg de volgende code toe:

    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;
        }
    }
    

    Met de voorgaande code wordt een implementatie gemaakt van IEmailSender die de inhoud van het bericht naar de console schrijft. In een echte implementatie SendEmailAsync maakt u verbinding met een externe e-mailservice of een andere actie om e-mail te verzenden.

  3. Voeg in Program.cs de gemarkeerde regels toe:

    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();
    

    Het voorgaande registreert EmailSender zich als een IEmailSender in het afhankelijkheidsinjectiesysteem.

De wijzigingen in het registratieformulier testen

Dat is alles! Laten we de wijzigingen in het registratieformulier en de bevestigingsmail testen.

  1. Zorg ervoor dat u al uw wijzigingen hebt opgeslagen.

  2. Bouw in het terminalvenster het project en voer de app uit met dotnet run.

  3. Ga in uw browser naar de app. Selecteer Afmelden als u bent aangemeld.

  4. Selecteer Registreren en gebruik het bijgewerkte formulier om een nieuwe gebruiker te registreren.

    Notitie

    De validatiebeperkingen voor de velden Voornaam en Achternaam weerspiegelen de gegevensaantekeningen op de eigenschappen FirstName en LastName van InputModel.

  5. Nadat u zich hebt geregistreerd, wordt u omgeleid naar het bevestigingsscherm Registreren. Schuif in het terminalvenster omhoog om de console-uitvoer te vinden die er ongeveer als volgt uitziet:

    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>
    

    Navigeer met Ctrl+ naar de URL. Het bevestigingsscherm wordt weergegeven.

    Notitie

    Als u GitHub Codespaces gebruikt, moet u mogelijk toevoegen -7192 aan het eerste deel van de doorgestuurde URL. Bijvoorbeeld: scaling-potato-5gr4j4-7192.preview.app.github.dev.

  6. Selecteer Aanmelden en meld u aan met de nieuwe gebruiker. De header van de app bevat nu Hallo, [voornaam] [achternaam]!.

  7. Klik in het deelvenster SQL Server in VS Code met de rechtermuisknop op de RazorPagesPizza-database en selecteer Nieuwe query. Voer in het tabblad dat wordt weergegeven de volgende query in en druk op Ctrl+Shift+E om deze uit te voeren.

    SELECT UserName, Email, FirstName, LastName
    FROM dbo.AspNetUsers
    

    Er wordt een tabblad met resultaten weergegeven die er ongeveer als volgt uitzien:

    Gebruikersnaam E-mailen FirstName LastName
    kai.klein@contoso.com kai.klein@contoso.com
    jana.heinrich@contoso.com jana.heinrich@contoso.com Jana Heinrich

    De eerste gebruiker die is geregistreerd voordat u het schema toevoegt FirstName en LastName aan het schema toevoegt. De gekoppelde AspNetUsers tabelrecord bevat dus geen gegevens in deze kolommen.

De wijzigingen in het profielbeheerformulier testen

U moet ook de wijzigingen testen die u hebt aangebracht in het profielbeheerformulier.

  1. Meld u in de web-app aan met de eerste gebruiker die u hebt gemaakt.

  2. Selecteer de koppeling Hallo, ! om naar het profielbeheerformulier te navigeren.

    Notitie

    De koppeling wordt niet correct weergegeven omdat de rij van de tabel AspNetUsers voor deze gebruiker geen waarden voor FirstName en LastName bevat.

  3. Voer geldige waarden in voor de Voornaam en Achternaam. Selecteer Opslaan.

    De header van de app wordt nu gewijzigd in Hallo, [voornaam] [achternaam]!.

  4. Als u de app wilt stoppen, drukt u op Ctrl+C in het terminalvenster in VS Code.

Samenvatting

In deze eenheid hebt u de identiteit aangepast om aangepaste gebruikersgegevens op te slaan. U hebt ook de bevestigings-e-mail aangepast. In de volgende les leert u meer over het implementeren van meervoudige verificatie in Identiteit.