Gyakorlat – Identitás testreszabása

Befejeződött

Az előző leckében megtanulta, hogyan működik a testreszabás az ASP.NET Core Identityben. Ebben a leckében kiterjeszti az Identitás adatmodellt, és elvégezheti a megfelelő felhasználói felületi módosításokat.

A felhasználói fiók adatainak testreszabása

Ebben a szakaszban az alapértelmezett Razor-osztálytár helyett az Identitás felhasználói felületének fájljait fogja létrehozni és testre szabni.

  1. Adja meg a projekt által módosítandó felhasználói regisztrációs fájlokat:

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

    A fenti parancsban:

    • A --dbContext beállítás adja meg az eszköznek a DbContext osztályból származtatott RazorPagesPizzaAuth nevű osztály információit.
    • A --files beállítás azoknak az egyedi fájloknak a pontosvesszővel tagolt listáját adja meg, amelyeket fel kell venni az Identity területre.
    • A --userClass beállítás eredménye az IdentityUser osztályból származtatott RazorPagesPizzaUser nevű osztály létrehozása.
    • A --force beállítás hatására az Identitás területen meglévő fájlok felülíródnak.

    Tipp

    Futtassa a következő parancsot a projekt gyökeréből a beállítás érvényes értékeinek megtekintéséhez --files : dotnet aspnet-codegenerator identity --listFiles

    Az alábbi fájlok lettek hozzáadva az Areas/Identity könyvtárhoz:

    • Data/
      • RazorPagesPizzaUser.cs
    • 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

    Ugyanakkor a Data/RazorPagesPizzaAuth.cs fájl, amely már a parancs futtatása előtt is létezett, felül lett írva, mert a --force beállítást használtuk. A RazorPagesPizzaAuth osztály deklarációja most az újonnan létrehozott RazorPagesPizzaUser felhasználótípusra hivatkozik:

    public class RazorPagesPizzaAuth : IdentityDbContext<RazorPagesPizzaUser>
    

    A EnableAuthenticator és ConfirmEmail a Razor-oldal állványzatú volt, de csak a modul későbbi részében módosultak.

  2. A-ben Program.csa hívásnak AddDefaultIdentity tisztában kell lennie az új identitásfelhasználói típussal. Foglalja bele az alábbi kiemelt módosításokat. (Az olvashatóság érdekében újraformált példa.)

    using Microsoft.AspNetCore.Identity;
    using Microsoft.EntityFrameworkCore;
    using RazorPagesPizza.Areas.Identity.Data;
    
    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();
    
  3. Frissítsen Pages/Shared/_LoginPartial.cshtml az alábbi kiemelt módosítások felülre való beépítéséhez. Mentse a módosításokat.

    @using Microsoft.AspNetCore.Identity
    @using RazorPagesPizza.Areas.Identity.Data
    @inject SignInManager<RazorPagesPizzaUser> SignInManager
    @inject UserManager<RazorPagesPizzaUser> UserManager
    
    <ul class="navbar-nav">
    

    Az iménti módosítások megváltoztatják az @inject direktívákban a SignInManager<T> és a UserManager<T> számára átadott felhasználótípust. Az alapértelmezett IdentityUser típus helyett már RazorPagesPizzaUser típusú felhasználókra hivatkoznak. A @using direktíva a RazorPagesPizzaUser hivatkozások feloldásához lett felvéve.

    A Pages/Shared/_LoginPartial.cshtml fájl fizikailag az Identity területen kívül helyezkedik el. Az állványeszköz tehát nem frissítette automatikusan a fájlt. A megfelelő módosításokat manuálisan kell elvégezni.

    Tipp

    A _LoginPartial.cshtml fájlt annak manuális szerkesztése helyett törölheti is a generáló eszköz futtatása előtt. A _LoginPartial.cshtml fájl újra létrejön az új RazorPagesPizzaUser osztályra mutató hivatkozásokkal.

  4. Módosítsa az Areas/Identity/Data/RazorPagesPizzaUser.cs fájlt a további felhasználói profil-adatok tárolásának és lekérésének támogatásához. Hajtsa végre a következő módosításokat:

    1. Vegye fel a FirstName és a LastName tulajdonságot:

      public class RazorPagesPizzaUser : IdentityUser
      {
          [Required]
          [MaxLength(100)]
          public string FirstName { get; set; } = string.Empty;
      
          [Required]
          [MaxLength(100)]
          public string LastName { get; set; } = string.Empty;
      }
      

      A fenti kódrészletben a tulajdonságok további oszlopoknak felelnek meg, amelyeket a mögöttes AspNetUsers táblában kell létrehozni. Mindkét tulajdonság megadása kötelező, ezért a [Required] attribútummal vannak ellátva. Ezen felül a [MaxLength] attribútum alapján legfeljebb 100 karakterből álló sztring engedélyezett. A mögöttes táblaoszlop adattípusa ennek megfelelően lesz definiálva. Az alapértelmezett érték van string.Empty hozzárendelve, mivel a null értékű környezet engedélyezve van ebben a projektben, és a tulajdonságok nem null értékű sztringek.

    2. A fájl elején szúrja be az alábbi using utasítást.

      using System.ComponentModel.DataAnnotations;
      

      A fenti kód a FirstName és a LastName tulajdonságra alkalmazott adatjegyzet-attribútumokat oldja fel.

Az adatbázis frissítése

Most, hogy végrehajtotta a modell módosításait, a kapcsolódó módosításokat végre kell hajtani az adatbázison.

  1. Győződjön meg arról, hogy az összes módosítás mentve van.

  2. Hozzon létre és alkalmazzon egy EF Core-migrációt a mögöttes adattár frissítéséhez:

    dotnet ef migrations add UpdateUser
    dotnet ef database update
    

    Az UpdateUser EF Core-migráció egy DDL módosítási szkriptet alkalmazott az AspNetUsers tábla sémájára. Pontosabban a FirstName és a LastName oszlopot adta hozzá, ahogyan a migráció kimenetének alábbi részletében látható:

    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. Vizsgálja meg az adatbázist az EF Core-migrálás UpdateUser táblasémára AspNetUsers gyakorolt hatásának elemzéséhez.

    A SQL Server panelen bontsa ki a dbo Oszlopok csomópontját. AspNetUsers tábla.

    Az AspNetUsers tábla sémájának képernyőképe.

    A FirstName osztály és LastName tulajdonságai RazorPagesPizzaUser az FirstName előző képen szereplő és LastName oszlopnak felelnek meg. A nvarchar(100) adattípus a [MaxLength(100)] attribútumok miatt lett megadva a két oszlop mindegyikéhez. A nem null kényszer azért lett hozzáadva, mert FirstNameLastName és az osztályban nem null értékű sztringek. A meglévő sorok üres sztringeket tartalmaznak az új oszlopokban.

A felhasználói regisztrációs űrlap testreszabása

Új oszlopokat adott hozzá a és LastNamea elemhezFirstName. Most szerkesztenie kell a felhasználói felületet, hogy egyező mezőket jelenítsen meg a regisztrációs űrlapon.

  1. Illessze be az alábbi kijelölt kódot az Areas/Identity/Pages/Account/Register.cshtml fájlba:

    <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"></div>
        <div class="form-floating">
            <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">
            <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">
            <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" />
            <label asp-for="Input.Email"></label>
            <span asp-validation-for="Input.Email" class="text-danger"></span>
        </div>
    

    A fenti kóddal az Utónév és a Vezetéknév szövegbeviteli mezőt vette fel a felhasználói regisztrációs űrlapra.

  2. Az Areas/Identity/Pages/Account/Register.cshtml.cs fájlba vegye fel a név szövegbeviteli mezőinek támogatását.

    1. A beágyazott InputModel osztályhoz adja meg a FirstName és a LastName tulajdonságot:

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

      A [Display] attribútumok a szövegbeviteli mezőkkel társítandó címkék szövegét adják meg.

    2. Módosítsa az OnPostAsync metódust a RazorPagesPizza objektum FirstName és LastName tulajdonságának beállításához. Adja hozzá a következő kiemelt sorokat:

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

      A fenti módosítás a regisztrációs űrlapon bevitt felhasználói adatokra állítja be a FirstName és a LastName tulajdonságot.

A webhely fejlécének testreszabása

Módosítsa úgy a Pages/Shared/_LoginPartial.cshtml fájlt, hogy megjelenítse a felhasználói regisztráció során bekért utónevet és vezetéknevet. Az alábbi kódrészlet kiemelt soraira lesz szükség:

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

A profilkezelési űrlap testreszabása

Az új mezőket hozzáadta a felhasználói regisztrációs űrlaphoz, de a profilkezelési űrlaphoz is hozzá kell adnia őket, hogy a meglévő felhasználók szerkeszthesse őket.

  1. Az Areas/Identity/Pages/Account/Manage/Index.cshtml fájlba illessze be az alábbi kódot. Mentse a módosításokat.

    <form id="profile-form" method="post">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-floating">
            <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">
            <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">
            <input asp-for="Username" class="form-control" disabled />
            <label asp-for="Username" class="form-label"></label>
        </div>
    
  2. Végezze el az alábbi módosításokat az Areas/Identity/Pages/Account/Manage/Index.cshtml.cs fájlban a szövegbeviteli mezők támogatásához.

    1. A beágyazott InputModel osztályhoz adja meg a FirstName és a LastName tulajdonságot:

      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; }
      
          [Phone]
          [Display(Name = "Phone number")]
          public string PhoneNumber { get; set; }
      }
      
    2. Építse be a kiemelt módosításokat az LoadAsync metódusba:

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

      A fenti kód az utó- és vezetéknév lekérését támogatja a profilkezelési űrlap megfelelő mezőiben való megjelenítéshez.

    3. Építse be a kiemelt módosításokat az OnPostAsync metódusba. Mentse a módosításokat.

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

      A fenti kód az utó- és vezetéknévnek az adatbázis AspNetUsers táblájában végzett módosítását támogatja.

A megerősítő e-mail küldőjének konfigurálása

A megerősítő e-mail elküldéséhez létre kell hoznia egy implementációt IEmailSender , és regisztrálnia kell azt a függőséginjektálási rendszerben. Az egyszerűség érdekében az implementáció valójában nem küld e-mailt egy SMTP-kiszolgálónak. Csak az e-mail-tartalmat írja a konzolra.

  1. Mivel az e-mailt egyszerű szövegben fogja megtekinteni a konzolon, a létrehozott üzenetet úgy kell módosítania, hogy kizárja a HTML-kódolású szöveget. A Areas/Identity/Pages/Account/Register.cshtml.cs területen keresse meg a következő kódot:

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

    Módosítsa a következőre:

    await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
        $"Please confirm your account by visiting the following URL:\r\n\r\n{callbackUrl}");
    
  2. Az Explorer panelen kattintson a jobb gombbal a Szolgáltatások mappára, és hozzon létre egy új fájlt EmailSender.cs néven. Nyissa meg a fájlt, és adja hozzá a következő kódot:

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

    Az előző kód létrehoz egy implementációt IEmailSender , amely az üzenet tartalmát írja a konzolra. Egy valós implementációban SendEmailAsync egy külső levelezőszolgáltatáshoz vagy más művelethez csatlakozna az e-mailek küldéséhez.

  3. A Program.cs fájlban adja hozzá a kiemelt sorokat:

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

    Az előző a függőséginjektálási EmailSenderIEmailSender rendszerben regisztrálja magát.

A regisztrációs űrlap módosításainak tesztelése

Ez minden! Teszteljük a regisztrációs űrlap módosításait és a megerősítő e-mailt.

  1. Győződjön meg arról, hogy az összes módosítást mentette.

  2. A terminálpanelen hozza létre a projektet, és futtassa az alkalmazást a következővel: dotnet run.

  3. Nyissa meg az alkalmazást a böngészőben. Ha még be van jelentkezve, válassza a Kijelentkezés lehetőséget.

  4. Válassza a Regisztráció lehetőséget, és regisztráljon új felhasználót a módosított űrlappal.

    Megjegyzés

    Az Utónév és a Vezetéknév mező érvényesítési megkötései az InputModelFirstName és LastName tulajdonságának adatjegyzeteit tükrözik.

  5. A regisztrációt követően a rendszer átirányítja a Regisztráció megerősítő képernyőre. A terminálablakban görgessen felfelé a következőhöz hasonló konzolkimenet megkereséséhez:

    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>
    

    Navigáljon az URL-címre a Ctrl billentyűt lenyomva+tartva. Megjelenik a megerősítést kérő képernyő.

    Megjegyzés

    Ha GitHub Codespacest használ, előfordulhat, hogy hozzá kell adnia -7192 a továbbított URL első részéhez. Például: scaling-potato-5gr4j4-7192.preview.app.github.dev.

  6. Válassza a Bejelentkezés lehetőséget, és jelentkezzen be az új felhasználóval. Az alkalmazás fejlécében most a Hello, [Utónév] [Vezetéknév]! üzenet jelenik meg.

  7. A VS Code SQL Server paneljén kattintson a jobb gombbal a RazorPagesPizza adatbázisra, és válassza az Új lekérdezés lehetőséget. A megjelenő lapon írja be a következő lekérdezést, és a CtrlShift+Ebillentyűkombinációt+ lenyomva futtassa.

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

    Megjelenik a következőhöz hasonló eredményekkel rendelkező lap:

    Felhasználónév E-mail FirstName LastName
    kai.klein@contoso.com kai.klein@contoso.com
    jana.heinrich@contoso.com jana.heinrich@contoso.com Jana Heinrich

    Az első felhasználó a FirstName és a LastName sémához adása előtt regisztrált. A társított AspNetUsers táblarekordnak tehát nincsenek adatai ezekben az oszlopokban.

A profilkezelési űrlap módosításainak tesztelése

Tesztelje a profilkezelési űrlapon végrehajtott módosításokat is.

  1. A webalkalmazásban jelentkezzen be az első létrehozott felhasználóval.

  2. Válassza a Hello, ! hivatkozást a profilkezelési űrlapra való navigáláshoz.

    Megjegyzés

    A hivatkozás azért nem jelenik meg helyesen, mert az AspNetUsers táblának az ehhez a felhasználóhoz tartozó sora nem tartalmazza a FirstName és a LastName értéket.

  3. Adja meg az Utónév és a Vezetéknév érvényes értékét. Válassza a Mentés lehetőséget.

    Az alkalmazás fejlécében a Hello, [Utónév] [Vezetéknév]! módosított üzenet jelenik meg.

  4. Az alkalmazás leállításához nyomja le a CtrlCbillentyűkombinációt+ a VS Code terminálablakában.

Összefoglalás

Ebben a leckében testre szabta az identitást az egyéni felhasználói adatok tárolásához. A megerősítő e-mailt is testreszabta. A következő leckében megismerheti a többtényezős hitelesítés implementálását az Identityben.