Adicionar, baixar e excluir dados de usuário personalizados para Identity em um projeto de ASP.NET Core

Este artigo mostra como:

  • Adicione dados de usuário personalizados a um aplicativo Web ASP.NET Core.
  • Marque o modelo de dados do usuário personalizado com o PersonalDataAttribute atributo para que ele esteja disponível automaticamente para download e exclusão. Fazer com que os dados possam ser baixados e excluídos ajuda a atender aos requisitos do RGPD .

O exemplo de projeto é criado a partir de um aplicativo Web Razor Pages, mas as instruções são semelhantes para um aplicativo Web ASP.NET Core MVC.

Exibir ou baixar código de exemplo (como baixar)

Prerequisites

SDK do .NET 10.0

Início Rápido: Adicionar duas propriedades personalizadas

Para o caso comum de adição de duas propriedades personalizadas, como FirstName e LastName:

  1. Criar um novo projeto ASP.NET Core com autenticação de Contas Individuais
  2. Faça o scaffolding de Identity para substituir as páginas Registrar e Gerenciar/Índice
  3. Adicione propriedades personalizadas, como FirstName e LastName à classe de usuário, com o [PersonalData] atributo.
  4. Atualize as páginas Registrar e Gerenciar/Índice para incluir campos de entrada para suas propriedades.
  5. Crie e aplique uma migração.
  6. Registro de teste e gerenciamento de perfil.

As seções abaixo fornecem instruções passo a passo detalhadas para esse processo.

Criar um aplicativo Web

Você pode criar um aplicativo web Razor Pages ou MVC. Ambos usam a mesma IdentityRazor interface do Pages.

Razor Páginas

  • No menu Arquivo do Visual Studio, selecione Novo>Projeto/Solução....
  • Selecione Aplicativo Web ASP.NET Core (Razor Páginas)>Avançar
  • Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download . Selecione Próximo.
  • Selecione tipo de autenticação>Contas individuais>Criar
  • Compile e execute o projeto.

MVC

  • No menu Arquivo do Visual Studio, selecione Novo>Projeto/Solução....
  • Selecione ASP.NET Core Aplicativo Web (Modelo-View-Controller)>Avançar
  • Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download . Selecione Próximo.
  • Selecione Tipo de autenticação>Contas individuais>Criar
  • Compile e execute o projeto.

Note

Identity A interface do usuário é implementada como uma Razor Biblioteca de Classes. Quando você cria um projeto MVC com autenticação, as páginas Identity são fornecidas pela biblioteca de classes Razor, o que significa que seu projeto MVC usa páginas Razor para Identity, embora o restante do projeto use controladores e exibições MVC.

Execute o scaffolder do Identity

  • Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto >Add>New Scaffolded Item.
  • No painel esquerdo da caixa de diálogo Adicionar Scaffold , selecione Identity>Adicionar.
  • Na caixa de diálogo Adicionar Identity, as seguintes opções:
    • Selecione o arquivo ~/Pages/Shared/_Layout.cshtml de layout existente para Razor Páginas ou ~/Views/Shared/_Layout.cshtml para MVC
    • Selecione os seguintes arquivos para substituir:
      • Account/Register
      • Account/Manage/Index
    • Selecione o + botão para criar uma nova classe de contexto de dados. Aceite o tipo (WebApp1.Models.WebApp1Context se o projeto for denominado WebApp1).
    • Selecione o + botão para criar uma nova classe user. Aceite o tipo (WebApp1User se o projeto se chamar WebApp1) >Adicionar.
  • Selecione Adicionar.

Siga as instruções em Migrações, UseAuthentication e layout para executar as seguintes etapas:

  • Crie uma migração e atualize o banco de dados.
  • Adicione UseAuthentication a Program.cs
  • Adicione <partial name="_LoginPartial" /> ao arquivo de layout.
  • Teste o aplicativo:
    • Registrar um usuário
    • Selecione o novo nome de usuário (ao lado do link logoff ). Talvez seja necessário expandir a janela ou selecionar o ícone da barra de navegação para mostrar o nome de usuário e outros links.
    • Selecione a guia Dados Pessoais .
    • Selecione o botão Baixar e examine o PersonalData.json arquivo.
    • Teste o botão Excluir , que exclui o usuário conectado.

Adicionar dados de usuário personalizados ao BD Identity

Atualize a IdentityUser classe derivada com propriedades personalizadas. Se você nomeou o projeto WebApp1, o arquivo será nomeado Areas/Identity/Data/WebApp1User.cs. Atualize o arquivo com o seguinte código:

using Microsoft.AspNetCore.Identity;

namespace WebApp1.Areas.Identity.Data;

public class WebApp1User : IdentityUser
{
    [PersonalData]
    public string? Name { get; set; }
    [PersonalData]
    public DateTime DOB { get; set; }
}

As propriedades com o atributo PersonalData são:

  • Excluído quando o Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtmlRazor Page chama UserManager.Delete.
  • Incluído nos dados baixados pelo Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtmlRazor Page.

Atualizar a página Account/Manage/Index.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Manage/Index.cshtml.cs com o seguinte código destacado:

public class IndexModel : PageModel
{
    private readonly UserManager<WebApp1User> _userManager;
    private readonly SignInManager<WebApp1User> _signInManager;

    public IndexModel(
        UserManager<WebApp1User> userManager,
        SignInManager<WebApp1User> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    /// <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>
    public string Username { get; set; }

    // Remaining API warnings omited.

    [TempData]
    public string StatusMessage { get; set; }

    [BindProperty]
    public InputModel Input { get; set; }

    public class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Birth Date")]
        [DataType(DataType.Date)]
        public DateTime DOB { get; set; }

        [Phone]
        [Display(Name = "Phone number")]
        public string PhoneNumber { get; set; }
    }

    private async Task LoadAsync(WebApp1User user)
    {
        var userName = await _userManager.GetUserNameAsync(user);
        var phoneNumber = await _userManager.GetPhoneNumberAsync(user);

        Username = userName;

        Input = new InputModel
        {
            Name = user.Name,
            DOB = user.DOB,
            PhoneNumber = phoneNumber
        };
    }

    public async Task<IActionResult> OnGetAsync()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }

        await LoadAsync(user);
        return Page();
    }

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

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

        if (Input.Name != user.Name)
        {
            user.Name = Input.Name;
        }

        if (Input.DOB != user.DOB)
        {
            user.DOB = Input.DOB;
        }

        await _userManager.UpdateAsync(user);
        await _signInManager.RefreshSignInAsync(user);
        StatusMessage = "Your profile has been updated";
        return RedirectToPage();
    }
}

Atualize o Areas/Identity/Pages/Account/Manage/Index.cshtml com a seguinte marcação destacada:

@page
@model IndexModel
@{
    ViewData["Title"] = "Profile";
    ViewData["ActivePage"] = ManageNavPages.Index;
}

<h3>@ViewData["Title"]</h3>
<partial name="_StatusMessage" for="StatusMessage" />
<div class="row">
    <div class="col-md-6">
        <form id="profile-form" method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-floating">
                <input asp-for="Username" class="form-control" disabled />
                <label asp-for="Username" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.Name" class="form-control" />
                <label asp-for="Input.Name" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.DOB" class="form-control" />
                <label asp-for="Input.DOB" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.PhoneNumber" class="form-control" />
                <label asp-for="Input.PhoneNumber" class="form-label"></label>
                <span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
            </div>
            <button id="update-profile-button" type="submit" class="w-100 btn btn-lg btn-primary">Save</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Atualizar a página Account/Register.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Register.cshtml.cs com o seguinte código destacado:

    public class RegisterModel : PageModel
    {
        private readonly SignInManager<WebApp1User> _signInManager;
        private readonly UserManager<WebApp1User> _userManager;
        private readonly IUserStore<WebApp1User> _userStore;
        private readonly IUserEmailStore<WebApp1User> _emailStore;
        private readonly ILogger<RegisterModel> _logger;
        private readonly IEmailSender _emailSender;

        public RegisterModel(
            UserManager<WebApp1User> userManager,
            IUserStore<WebApp1User> userStore,
            SignInManager<WebApp1User> signInManager,
            ILogger<RegisterModel> logger,
            IEmailSender emailSender)
        {
            _userManager = userManager;
            _userStore = userStore;
            _emailStore = GetEmailStore();
            _signInManager = signInManager;
            _logger = logger;
            _emailSender = emailSender;
        }

        /// <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>
        [BindProperty]
        public InputModel Input { get; set; }

        // Remaining API warnings omited.
        public string ReturnUrl { get; set; }

        public IList<AuthenticationScheme> ExternalLogins { get; set; }

        public class InputModel
        {
            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "Full name")]
            public string Name { get; set; }

            [Required]
            [Display(Name = "Birth Date")]
            [DataType(DataType.Date)]
            public DateTime DOB { get; set; }

            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }

            [Required]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }

            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }
        }


        public async Task OnGetAsync(string returnUrl = null)
        {
            ReturnUrl = returnUrl;
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        }

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl ??= Url.Content("~/");
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
            {
                var user = CreateUser();

                user.Name = Input.Name;
                user.DOB = Input.DOB;

                await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
                await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
                var result = await _userManager.CreateAsync(user, Input.Password);

                if (result.Succeeded)
                {
                    _logger.LogInformation("User created a new account with password.");

                    var userId = await _userManager.GetUserIdAsync(user);
                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                    var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                        protocol: Request.Scheme);

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

                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
                    {
                        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                    }
                    else
                    {
                        await _signInManager.SignInAsync(user, isPersistent: false);
                        return LocalRedirect(returnUrl);
                    }
                }
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError(string.Empty, error.Description);
                }
            }

            // If we got this far, something failed, redisplay form
            return Page();
        }

        private WebApp1User CreateUser()
        {
            try
            {
                return Activator.CreateInstance<WebApp1User>();
            }
            catch
            {
                throw new InvalidOperationException($"Can't create an instance of '{nameof(WebApp1User)}'. " +
                    $"Ensure that '{nameof(WebApp1User)}' is not an abstract class and has a parameterless constructor, or alternatively " +
                    $"override the register page in /Areas/Identity/Pages/Account/Register.cshtml");
            }
        }

        private IUserEmailStore<WebApp1User> GetEmailStore()
        {
            if (!_userManager.SupportsUserEmail)
            {
                throw new NotSupportedException("The default UI requires a user store with email support.");
            }
            return (IUserEmailStore<WebApp1User>)_userStore;
        }
    }
}

Atualize o Areas/Identity/Pages/Account/Register.cshtml com a seguinte marcação destacada:

@page
@model RegisterModel
@{
    ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>

<div class="row">
    <div class="col-md-4">
        <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.Name" class="form-control" />
                <label asp-for="Input.Name"></label>
                <span asp-validation-for="Input.Name" class="text-danger"></span>
            </div>
            <div class="form-floating">
                <input asp-for="Input.DOB" class="form-control" />
                <label asp-for="Input.DOB"></label>
                <span asp-validation-for="Input.DOB" 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>
            <div class="form-floating">
                <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" />
                <label asp-for="Input.Password"></label>
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-floating">
                <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" />
                <label asp-for="Input.ConfirmPassword"></label>
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
        </form>
    </div>
    <div class="col-md-6 col-md-offset-2">
        <section>
            <h3>Use another service to register.</h3>
            <hr />
            @{
                if ((Model.ExternalLogins?.Count ?? 0) == 0)
                {
                    <div>
                        <p>
                            There are no external authentication services configured. See this <a href="https://go.microsoft.com/fwlink/?LinkID=532715">article
                            about setting up this ASP.NET application to support logging in via external services</a>.
                        </p>
                    </div>
                }
                else
                {
                    <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                        <div>
                            <p>
                                @foreach (var provider in Model.ExternalLogins!)
                                {
                                    <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                                }
                            </p>
                        </div>
                    </form>
                }
            }
        </section>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Compile o projeto.

Atualizar o layout

Consulte as alterações de Layout para obter instruções para adicionar links de entrada e de saída a cada página.

Adicionar uma migração para os dados de usuário personalizados

Na Console do Gerenciador de Pacotes do Visual Studio Gerenciador de Pacotes:

Add-Migration CustomUserData
Update-Database

Testar criar, exibir, baixar, excluir dados de usuário personalizados

Teste o aplicativo:

  • Registre um novo usuário.
  • Exiba os dados personalizados do usuário na /Identity/Account/Manage página.
  • Baixe e exiba os dados pessoais dos usuários da /Identity/Account/Manage/PersonalData página.

Troubleshooting

Caso se depare com problemas:

Sintoma Causa provável Solução
Campos personalizados não aparecem no formulário de registro Foi esquecido atualizar o Register.cshtml Verifique se você fez o scaffolding e modificou Areas/Identity/Pages/Account/Register.cshtml
Dados personalizados não salvos Esqueceu de adicionar a migração ou atualizar o banco de dados Executar dotnet ef migrations add CustomUserData , em seguida, dotnet ef database update
Campos personalizados que não estão nos dados baixados Atributo [PersonalData] ausente Adicionar [PersonalData] atributo a propriedades em sua classe de usuário
Erros de compilação após o scaffolding Incompatibilidade de versão do pacote Verifique se todos os Identity pacotes correspondem à versão da estrutura de destino

SDK do .NET 9

Note

Os exemplos de código e as instruções para .NET 9 fazem referência à pasta de exemplo 10.x. O código é idêntico entre .NET 9 e .NET 10 para esse cenário. Somente a estrutura de destino e as versões do pacote diferem no arquivo de projeto.

Início rápido: Adicionar duas propriedades personalizadas

Para o caso comum de adição de duas propriedades personalizadas, como FirstName e LastName:

  1. Criar um novo projeto ASP.NET Core com autenticação de Contas Individuais
  2. Faça o scaffolding de Identity para substituir as páginas Registrar e Gerenciar/Índice
  3. Adicione propriedades personalizadas, como FirstName e LastName à classe de usuário, com o [PersonalData] atributo.
  4. Atualize as páginas Registrar e Gerenciar/Índice para incluir campos de entrada para suas propriedades
  5. Criar e aplicar uma migração
  6. Testar o registro e o gerenciamento de perfil

As seções abaixo fornecem instruções passo a passo detalhadas para esse processo.

Criar um aplicativo Web

Você pode criar um aplicativo Web Razor Pages ou MVC. Ambos usam a mesma IdentityRazor interface de usuário do Pages.

Razor Páginas

  • No menu Visual Studio File, selecione New>Project. Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download .
  • Selecione Aplicativo Web ASP.NET Core>Avançar
  • Selecione Tipo de autenticação>Contas individuais>Criar
  • Compile e execute o projeto.

MVC

  • No menu Visual Studio File, selecione New>Project. Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download .
  • Selecione ASP.NET Core Aplicativo Web (Modelo-View-Controller)>Avançar
  • Selecione Tipo de autenticação>Contas individuais>Criar
  • Compile e execute o projeto.

Note

Identity A interface do usuário é implementada como uma Razor Biblioteca de Classes. Quando você cria um projeto MVC com autenticação, as páginas Identity são fornecidas pela biblioteca de classes Razor, o que significa que seu projeto MVC usa páginas Razor para Identity, mesmo que o restante do projeto use controladores e exibições MVC.

Execute o scaffolder do Identity

  • Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto >Add>New Scaffolded Item.
  • No painel esquerdo da caixa de diálogo Adicionar Scaffold , selecione Identity>Adicionar.
  • Na caixa de diálogo Adicionar Identity, as seguintes opções:
    • Selecione o arquivo ~/Pages/Shared/_Layout.cshtml de layout existente para Razor Páginas ou ~/Views/Shared/_Layout.cshtml para MVC
    • Selecione os seguintes arquivos para substituir:
      • Account/Register
      • Account/Manage/Index
    • Selecione o + botão para criar uma nova classe de contexto de dados. Aceite o tipo (WebApp1.Models.WebApp1Context se o projeto for denominado WebApp1).
    • Selecione o + botão para criar uma nova classe user. Aceite o tipo (WebApp1User se o projeto se chamar WebApp1) >Adicionar.
  • Selecione Adicionar.

Siga as instruções em Migrações, UseAuthentication e layout para executar as seguintes etapas:

  • Crie uma migração e atualize o banco de dados.
  • Adicione UseAuthentication a Program.cs
  • Adicione <partial name="_LoginPartial" /> ao arquivo de layout.
  • Teste o aplicativo:
    • Registrar um usuário
    • Selecione o novo nome de usuário (ao lado do link logoff ). Talvez seja necessário expandir a janela ou selecionar o ícone da barra de navegação para mostrar o nome de usuário e outros links.
    • Selecione a guia Dados Pessoais .
    • Selecione o botão Baixar e examine o PersonalData.json arquivo.
    • Teste o botão Excluir , que exclui o usuário conectado.

Adicionar dados de usuário personalizados ao BD Identity

Atualize a IdentityUser classe derivada com propriedades personalizadas. Se você nomeou o projeto WebApp1, o arquivo será nomeado Areas/Identity/Data/WebApp1User.cs. Atualize o arquivo com o seguinte código:

using Microsoft.AspNetCore.Identity;

namespace WebApp1.Areas.Identity.Data;

public class WebApp1User : IdentityUser
{
    [PersonalData]
    public string? Name { get; set; }
    [PersonalData]
    public DateTime DOB { get; set; }
}

As propriedades com o atributo PersonalData são:

  • Excluído quando o Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtmlRazor Page chama UserManager.Delete.
  • Incluído nos dados baixados pelo Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtmlRazor Page.

Atualizar a página Account/Manage/Index.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Manage/Index.cshtml.cs com o seguinte código destacado:

public class IndexModel : PageModel
{
    private readonly UserManager<WebApp1User> _userManager;
    private readonly SignInManager<WebApp1User> _signInManager;

    public IndexModel(
        UserManager<WebApp1User> userManager,
        SignInManager<WebApp1User> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    /// <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>
    public string Username { get; set; }

    // Remaining API warnings omited.

    [TempData]
    public string StatusMessage { get; set; }

    [BindProperty]
    public InputModel Input { get; set; }

    public class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Birth Date")]
        [DataType(DataType.Date)]
        public DateTime DOB { get; set; }

        [Phone]
        [Display(Name = "Phone number")]
        public string PhoneNumber { get; set; }
    }

    private async Task LoadAsync(WebApp1User user)
    {
        var userName = await _userManager.GetUserNameAsync(user);
        var phoneNumber = await _userManager.GetPhoneNumberAsync(user);

        Username = userName;

        Input = new InputModel
        {
            Name = user.Name,
            DOB = user.DOB,
            PhoneNumber = phoneNumber
        };
    }

    public async Task<IActionResult> OnGetAsync()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }

        await LoadAsync(user);
        return Page();
    }

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

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

        if (Input.Name != user.Name)
        {
            user.Name = Input.Name;
        }

        if (Input.DOB != user.DOB)
        {
            user.DOB = Input.DOB;
        }

        await _userManager.UpdateAsync(user);
        await _signInManager.RefreshSignInAsync(user);
        StatusMessage = "Your profile has been updated";
        return RedirectToPage();
    }
}

Atualize o Areas/Identity/Pages/Account/Manage/Index.cshtml com a seguinte marcação destacada:

@page
@model IndexModel
@{
    ViewData["Title"] = "Profile";
    ViewData["ActivePage"] = ManageNavPages.Index;
}

<h3>@ViewData["Title"]</h3>
<partial name="_StatusMessage" for="StatusMessage" />
<div class="row">
    <div class="col-md-6">
        <form id="profile-form" method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-floating">
                <input asp-for="Username" class="form-control" disabled />
                <label asp-for="Username" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.Name" class="form-control" />
                <label asp-for="Input.Name" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.DOB" class="form-control" />
                <label asp-for="Input.DOB" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.PhoneNumber" class="form-control" />
                <label asp-for="Input.PhoneNumber" class="form-label"></label>
                <span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
            </div>
            <button id="update-profile-button" type="submit" class="w-100 btn btn-lg btn-primary">Save</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Atualizar a página Account/Register.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Register.cshtml.cs com o seguinte código destacado:

    public class RegisterModel : PageModel
    {
        private readonly SignInManager<WebApp1User> _signInManager;
        private readonly UserManager<WebApp1User> _userManager;
        private readonly IUserStore<WebApp1User> _userStore;
        private readonly IUserEmailStore<WebApp1User> _emailStore;
        private readonly ILogger<RegisterModel> _logger;
        private readonly IEmailSender _emailSender;

        public RegisterModel(
            UserManager<WebApp1User> userManager,
            IUserStore<WebApp1User> userStore,
            SignInManager<WebApp1User> signInManager,
            ILogger<RegisterModel> logger,
            IEmailSender emailSender)
        {
            _userManager = userManager;
            _userStore = userStore;
            _emailStore = GetEmailStore();
            _signInManager = signInManager;
            _logger = logger;
            _emailSender = emailSender;
        }

        /// <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>
        [BindProperty]
        public InputModel Input { get; set; }

        // Remaining API warnings omited.
        public string ReturnUrl { get; set; }

        public IList<AuthenticationScheme> ExternalLogins { get; set; }

        public class InputModel
        {
            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "Full name")]
            public string Name { get; set; }

            [Required]
            [Display(Name = "Birth Date")]
            [DataType(DataType.Date)]
            public DateTime DOB { get; set; }

            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }

            [Required]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }

            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }
        }


        public async Task OnGetAsync(string returnUrl = null)
        {
            ReturnUrl = returnUrl;
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        }

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl ??= Url.Content("~/");
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
            {
                var user = CreateUser();

                user.Name = Input.Name;
                user.DOB = Input.DOB;

                await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
                await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
                var result = await _userManager.CreateAsync(user, Input.Password);

                if (result.Succeeded)
                {
                    _logger.LogInformation("User created a new account with password.");

                    var userId = await _userManager.GetUserIdAsync(user);
                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                    var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                        protocol: Request.Scheme);

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

                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
                    {
                        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                    }
                    else
                    {
                        await _signInManager.SignInAsync(user, isPersistent: false);
                        return LocalRedirect(returnUrl);
                    }
                }
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError(string.Empty, error.Description);
                }
            }

            // If we got this far, something failed, redisplay form
            return Page();
        }

        private WebApp1User CreateUser()
        {
            try
            {
                return Activator.CreateInstance<WebApp1User>();
            }
            catch
            {
                throw new InvalidOperationException($"Can't create an instance of '{nameof(WebApp1User)}'. " +
                    $"Ensure that '{nameof(WebApp1User)}' is not an abstract class and has a parameterless constructor, or alternatively " +
                    $"override the register page in /Areas/Identity/Pages/Account/Register.cshtml");
            }
        }

        private IUserEmailStore<WebApp1User> GetEmailStore()
        {
            if (!_userManager.SupportsUserEmail)
            {
                throw new NotSupportedException("The default UI requires a user store with email support.");
            }
            return (IUserEmailStore<WebApp1User>)_userStore;
        }
    }
}

Atualize o Areas/Identity/Pages/Account/Register.cshtml com a seguinte marcação destacada:

@page
@model RegisterModel
@{
    ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>

<div class="row">
    <div class="col-md-4">
        <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.Name" class="form-control" />
                <label asp-for="Input.Name"></label>
                <span asp-validation-for="Input.Name" class="text-danger"></span>
            </div>
            <div class="form-floating">
                <input asp-for="Input.DOB" class="form-control" />
                <label asp-for="Input.DOB"></label>
                <span asp-validation-for="Input.DOB" 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>
            <div class="form-floating">
                <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" />
                <label asp-for="Input.Password"></label>
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-floating">
                <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" />
                <label asp-for="Input.ConfirmPassword"></label>
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
        </form>
    </div>
    <div class="col-md-6 col-md-offset-2">
        <section>
            <h3>Use another service to register.</h3>
            <hr />
            @{
                if ((Model.ExternalLogins?.Count ?? 0) == 0)
                {
                    <div>
                        <p>
                            There are no external authentication services configured. See this <a href="https://go.microsoft.com/fwlink/?LinkID=532715">article
                            about setting up this ASP.NET application to support logging in via external services</a>.
                        </p>
                    </div>
                }
                else
                {
                    <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                        <div>
                            <p>
                                @foreach (var provider in Model.ExternalLogins!)
                                {
                                    <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                                }
                            </p>
                        </div>
                    </form>
                }
            }
        </section>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Compile o projeto.

Atualizar o layout

Consulte as alterações de Layout para obter instruções para adicionar links de entrada e de saída a cada página.

Adicionar uma migração para os dados de usuário personalizados

Na Console do Gerenciador de Pacotes do Visual Studio Gerenciador de Pacotes:

Add-Migration CustomUserData
Update-Database

Testar criar, exibir, baixar, excluir dados de usuário personalizados

Teste o aplicativo:

  • Registre um novo usuário.
  • Exiba os dados personalizados do usuário na /Identity/Account/Manage página.
  • Baixe e exiba os dados pessoais dos usuários da /Identity/Account/Manage/PersonalData página.

Troubleshooting

Caso se depare com problemas:

Sintoma Causa provável Solução
Campos personalizados não aparecem no formulário de registro Esqueceu-se de atualizar Register.cshtml Verifique se você fez o scaffolding e modificou Areas/Identity/Pages/Account/Register.cshtml
Dados personalizados não salvos Esqueceu de adicionar a migração ou atualizar o banco de dados Executar dotnet ef migrations add CustomUserData , em seguida, dotnet ef database update
Campos personalizados que não estão nos dados baixados Atributo [PersonalData] ausente Adicionar [PersonalData] atributo a propriedades em sua classe de usuário
Erros de compilação após o scaffolding Incompatibilidade de versão do pacote Verifique se todos os Identity pacotes correspondem à versão da estrutura de destino

SDK do .NET 8

Note

Os exemplos de código e as instruções para .NET 8 fazem referência à pasta de exemplo 10.x. O código é idêntico entre .NET 8 e .NET 10 para esse cenário. Somente a estrutura de destino e as versões do pacote diferem no arquivo de projeto.

Início rápido: Adicionar duas propriedades personalizadas

Para um cenário simples em que você deseja adicionar apenas algumas propriedades personalizadas, como FirstName e LastName ao usuário Identity :

  1. Criar um novo projeto ASP.NET Core com autenticação de Contas Individuais
  2. Faça o scaffolding de Identity para substituir as páginas Registrar e Gerenciar/Índice
  3. Adicione suas propriedades personalizadas à classe de usuário (por exemplo, FirstName, ) LastNamecom o [PersonalData] atributo
  4. Atualize as páginas Registrar e Gerenciar/Índice para incluir campos de entrada para suas propriedades
  5. Criar e aplicar uma migração
  6. Testar o registro e o gerenciamento de perfil

As seções abaixo fornecem instruções passo a passo detalhadas para esse processo.

Criar um aplicativo Web

Você pode criar um aplicativo Web Razor Pages ou MVC. Ambos usam a mesma IdentityRazor interface de usuário do Pages.

Razor Páginas

  • No menu Visual Studio File, selecione New>Project. Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download .
  • Selecione Aplicativo Web ASP.NET Core>Avançar
  • Selecione Tipo de autenticação>Contas individuais>Criar
  • Compile e execute o projeto.

MVC

  • No menu Visual Studio File, selecione New>Project. Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download .
  • Selecione ASP.NET Core Aplicativo Web (Modelo-View-Controller)>Avançar
  • Selecione Tipo de autenticação>Contas individuais>Criar
  • Compile e execute o projeto.

Note

Identity A interface do usuário é implementada como uma Razor Biblioteca de Classes. Quando você cria um projeto MVC com autenticação, as páginas Identity são fornecidas pela biblioteca de classes Razor, o que significa que seu projeto MVC usa páginas Razor para Identity, mesmo que o restante do projeto use controladores e exibições MVC.

Execute o scaffolder do Identity

  • Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto >Add>New Scaffolded Item.
  • No painel esquerdo da caixa de diálogo Adicionar Scaffold , selecione Identity>Adicionar.
  • Na caixa de diálogo Adicionar Identity, as seguintes opções:
    • Selecione o arquivo ~/Pages/Shared/_Layout.cshtml de layout existente para Razor Páginas ou ~/Views/Shared/_Layout.cshtml para MVC
    • Selecione os seguintes arquivos para substituir:
      • Account/Register
      • Account/Manage/Index
    • Selecione o + botão para criar uma nova classe de contexto de dados. Aceite o tipo (WebApp1.Models.WebApp1Context se o projeto for denominado WebApp1).
    • Selecione o + botão para criar uma nova classe user. Aceite o tipo (WebApp1User se o projeto se chamar WebApp1) >Adicionar.
  • Selecione Adicionar.

Siga as instruções em Migrações, UseAuthentication e layout para executar as seguintes etapas:

  • Crie uma migração e atualize o banco de dados.
  • Adicione UseAuthentication a Program.cs
  • Adicione <partial name="_LoginPartial" /> ao arquivo de layout.
  • Teste o aplicativo:
    • Registrar um usuário
    • Selecione o novo nome de usuário (ao lado do link logoff ). Talvez seja necessário expandir a janela ou selecionar o ícone da barra de navegação para mostrar o nome de usuário e outros links.
    • Selecione a guia Dados Pessoais .
    • Selecione o botão Baixar e examine o PersonalData.json arquivo.
    • Teste o botão Excluir , que exclui o usuário conectado.

Adicionar dados de usuário personalizados ao BD Identity

Atualize a IdentityUser classe derivada com propriedades personalizadas. Se você nomeou o projeto WebApp1, o arquivo será nomeado Areas/Identity/Data/WebApp1User.cs. Atualize o arquivo com o seguinte código:

using Microsoft.AspNetCore.Identity;

namespace WebApp1.Areas.Identity.Data;

public class WebApp1User : IdentityUser
{
    [PersonalData]
    public string? Name { get; set; }
    [PersonalData]
    public DateTime DOB { get; set; }
}

As propriedades com o atributo PersonalData são:

  • Excluído quando o Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtmlRazor Page chama UserManager.Delete.
  • Incluído nos dados baixados pelo Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtmlRazor Page.

Atualizar a página Account/Manage/Index.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Manage/Index.cshtml.cs com o seguinte código destacado:

public class IndexModel : PageModel
{
    private readonly UserManager<WebApp1User> _userManager;
    private readonly SignInManager<WebApp1User> _signInManager;

    public IndexModel(
        UserManager<WebApp1User> userManager,
        SignInManager<WebApp1User> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    /// <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>
    public string Username { get; set; }

    // Remaining API warnings omited.

    [TempData]
    public string StatusMessage { get; set; }

    [BindProperty]
    public InputModel Input { get; set; }

    public class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Birth Date")]
        [DataType(DataType.Date)]
        public DateTime DOB { get; set; }

        [Phone]
        [Display(Name = "Phone number")]
        public string PhoneNumber { get; set; }
    }

    private async Task LoadAsync(WebApp1User user)
    {
        var userName = await _userManager.GetUserNameAsync(user);
        var phoneNumber = await _userManager.GetPhoneNumberAsync(user);

        Username = userName;

        Input = new InputModel
        {
            Name = user.Name,
            DOB = user.DOB,
            PhoneNumber = phoneNumber
        };
    }

    public async Task<IActionResult> OnGetAsync()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }

        await LoadAsync(user);
        return Page();
    }

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

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

        if (Input.Name != user.Name)
        {
            user.Name = Input.Name;
        }

        if (Input.DOB != user.DOB)
        {
            user.DOB = Input.DOB;
        }

        await _userManager.UpdateAsync(user);
        await _signInManager.RefreshSignInAsync(user);
        StatusMessage = "Your profile has been updated";
        return RedirectToPage();
    }
}

Atualize o Areas/Identity/Pages/Account/Manage/Index.cshtml com a seguinte marcação destacada:

@page
@model IndexModel
@{
    ViewData["Title"] = "Profile";
    ViewData["ActivePage"] = ManageNavPages.Index;
}

<h3>@ViewData["Title"]</h3>
<partial name="_StatusMessage" for="StatusMessage" />
<div class="row">
    <div class="col-md-6">
        <form id="profile-form" method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-floating">
                <input asp-for="Username" class="form-control" disabled />
                <label asp-for="Username" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.Name" class="form-control" />
                <label asp-for="Input.Name" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.DOB" class="form-control" />
                <label asp-for="Input.DOB" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.PhoneNumber" class="form-control" />
                <label asp-for="Input.PhoneNumber" class="form-label"></label>
                <span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
            </div>
            <button id="update-profile-button" type="submit" class="w-100 btn btn-lg btn-primary">Save</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Atualizar a página Account/Register.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Register.cshtml.cs com o seguinte código destacado:

    public class RegisterModel : PageModel
    {
        private readonly SignInManager<WebApp1User> _signInManager;
        private readonly UserManager<WebApp1User> _userManager;
        private readonly IUserStore<WebApp1User> _userStore;
        private readonly IUserEmailStore<WebApp1User> _emailStore;
        private readonly ILogger<RegisterModel> _logger;
        private readonly IEmailSender _emailSender;

        public RegisterModel(
            UserManager<WebApp1User> userManager,
            IUserStore<WebApp1User> userStore,
            SignInManager<WebApp1User> signInManager,
            ILogger<RegisterModel> logger,
            IEmailSender emailSender)
        {
            _userManager = userManager;
            _userStore = userStore;
            _emailStore = GetEmailStore();
            _signInManager = signInManager;
            _logger = logger;
            _emailSender = emailSender;
        }

        /// <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>
        [BindProperty]
        public InputModel Input { get; set; }

        // Remaining API warnings omited.
        public string ReturnUrl { get; set; }

        public IList<AuthenticationScheme> ExternalLogins { get; set; }

        public class InputModel
        {
            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "Full name")]
            public string Name { get; set; }

            [Required]
            [Display(Name = "Birth Date")]
            [DataType(DataType.Date)]
            public DateTime DOB { get; set; }

            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }

            [Required]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }

            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }
        }


        public async Task OnGetAsync(string returnUrl = null)
        {
            ReturnUrl = returnUrl;
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        }

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl ??= Url.Content("~/");
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
            {
                var user = CreateUser();

                user.Name = Input.Name;
                user.DOB = Input.DOB;

                await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
                await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
                var result = await _userManager.CreateAsync(user, Input.Password);

                if (result.Succeeded)
                {
                    _logger.LogInformation("User created a new account with password.");

                    var userId = await _userManager.GetUserIdAsync(user);
                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                    var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                        protocol: Request.Scheme);

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

                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
                    {
                        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                    }
                    else
                    {
                        await _signInManager.SignInAsync(user, isPersistent: false);
                        return LocalRedirect(returnUrl);
                    }
                }
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError(string.Empty, error.Description);
                }
            }

            // If we got this far, something failed, redisplay form
            return Page();
        }

        private WebApp1User CreateUser()
        {
            try
            {
                return Activator.CreateInstance<WebApp1User>();
            }
            catch
            {
                throw new InvalidOperationException($"Can't create an instance of '{nameof(WebApp1User)}'. " +
                    $"Ensure that '{nameof(WebApp1User)}' is not an abstract class and has a parameterless constructor, or alternatively " +
                    $"override the register page in /Areas/Identity/Pages/Account/Register.cshtml");
            }
        }

        private IUserEmailStore<WebApp1User> GetEmailStore()
        {
            if (!_userManager.SupportsUserEmail)
            {
                throw new NotSupportedException("The default UI requires a user store with email support.");
            }
            return (IUserEmailStore<WebApp1User>)_userStore;
        }
    }
}

Atualize o Areas/Identity/Pages/Account/Register.cshtml com a seguinte marcação destacada:

@page
@model RegisterModel
@{
    ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>

<div class="row">
    <div class="col-md-4">
        <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.Name" class="form-control" />
                <label asp-for="Input.Name"></label>
                <span asp-validation-for="Input.Name" class="text-danger"></span>
            </div>
            <div class="form-floating">
                <input asp-for="Input.DOB" class="form-control" />
                <label asp-for="Input.DOB"></label>
                <span asp-validation-for="Input.DOB" 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>
            <div class="form-floating">
                <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" />
                <label asp-for="Input.Password"></label>
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-floating">
                <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" />
                <label asp-for="Input.ConfirmPassword"></label>
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
        </form>
    </div>
    <div class="col-md-6 col-md-offset-2">
        <section>
            <h3>Use another service to register.</h3>
            <hr />
            @{
                if ((Model.ExternalLogins?.Count ?? 0) == 0)
                {
                    <div>
                        <p>
                            There are no external authentication services configured. See this <a href="https://go.microsoft.com/fwlink/?LinkID=532715">article
                            about setting up this ASP.NET application to support logging in via external services</a>.
                        </p>
                    </div>
                }
                else
                {
                    <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                        <div>
                            <p>
                                @foreach (var provider in Model.ExternalLogins!)
                                {
                                    <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                                }
                            </p>
                        </div>
                    </form>
                }
            }
        </section>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Compile o projeto.

Atualizar o layout

Consulte as alterações de Layout para obter instruções para adicionar links de entrada e de saída a cada página.

Adicionar uma migração para os dados de usuário personalizados

Na Console do Gerenciador de Pacotes do Visual Studio Gerenciador de Pacotes:

Add-Migration CustomUserData
Update-Database

Testar criar, exibir, baixar, excluir dados de usuário personalizados

Teste o aplicativo:

  • Registre um novo usuário.
  • Exiba os dados personalizados do usuário na /Identity/Account/Manage página.
  • Baixe e exiba os dados pessoais dos usuários da /Identity/Account/Manage/PersonalData página.

Troubleshooting

Caso se depare com problemas:

Sintoma Causa provável Solução
Campos personalizados não aparecem no formulário de registro Esqueceu-se de atualizar Register.cshtml Verifique se você fez o scaffolding e modificou Areas/Identity/Pages/Account/Register.cshtml
Dados personalizados não salvos Esqueceu de adicionar a migração ou atualizar o banco de dados Executar dotnet ef migrations add CustomUserData , em seguida, dotnet ef database update
Campos personalizados que não estão nos dados baixados Atributo [PersonalData] ausente Adicionar [PersonalData] atributo a propriedades em sua classe de usuário
Erros de compilação após o scaffolding Incompatibilidade de versão do pacote Verifique se todos os Identity pacotes correspondem à versão da estrutura de destino

SDK do .NET 6

Criar um Razor aplicativo Web

  • No menu Visual Studio File, selecione New>Project. Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download .
  • Selecione ASP.NET Core Aplicativo Web>OK
  • Selecione Aplicação Web>OK
  • Compile e execute o projeto.

Execute o scaffolder do Identity

  • Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto >Add>New Scaffolded Item.
  • No painel esquerdo da caixa de diálogo Adicionar Scaffold , selecione Identity>Adicionar.
  • Na caixa de diálogo Adicionar Identity, as seguintes opções:
    • Selecione o arquivo de layout existente ~/Pages/Shared/_Layout.cshtml
    • Selecione os seguintes arquivos para substituir:
      • Account/Register
      • Account/Manage/Index
    • Selecione o + botão para criar uma nova classe de contexto de dados. Aceite o tipo (WebApp1.Models.WebApp1Context se o projeto for denominado WebApp1).
    • Selecione o + botão para criar uma nova classe user. Aceite o tipo (WebApp1User se o projeto se chamar WebApp1) >Adicionar.
  • Selecione Adicionar.

Siga as instruções em Migrações, UseAuthentication e layout para executar as seguintes etapas:

  • Crie uma migração e atualize o banco de dados.
  • Adicione UseAuthentication a Program.cs
  • Adicione <partial name="_LoginPartial" /> ao arquivo de layout.
  • Teste o aplicativo:
    • Registrar um usuário
    • Selecione o novo nome de usuário (ao lado do link logoff ). Talvez seja necessário expandir a janela ou selecionar o ícone da barra de navegação para mostrar o nome de usuário e outros links.
    • Selecione a guia Dados Pessoais .
    • Selecione o botão Baixar e examine o PersonalData.json arquivo.
    • Teste o botão Excluir , que exclui o usuário conectado.

Adicionar dados de usuário personalizados ao BD Identity

Atualize a IdentityUser classe derivada com propriedades personalizadas. Se você nomeou o projeto WebApp1, o arquivo será nomeado Areas/Identity/Data/WebApp1User.cs. Atualize o arquivo com o seguinte código:

using Microsoft.AspNetCore.Identity;

namespace WebApp1.Areas.Identity.Data;

public class WebApp1User : IdentityUser
{
    [PersonalData]
    public string? Name { get; set; }
    [PersonalData]
    public DateTime DOB { get; set; }
}

As propriedades com o atributo PersonalData são:

  • Excluído quando o Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtmlRazor Page chama UserManager.Delete.
  • Incluído nos dados baixados pelo Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtmlRazor Page.

Atualizar a página Account/Manage/Index.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Manage/Index.cshtml.cs com o seguinte código destacado:

public class IndexModel : PageModel
{
    private readonly UserManager<WebApp1User> _userManager;
    private readonly SignInManager<WebApp1User> _signInManager;

    public IndexModel(
        UserManager<WebApp1User> userManager,
        SignInManager<WebApp1User> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    /// <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>
    public string Username { get; set; }

    // Remaining API warnings ommited.

    [TempData]
    public string StatusMessage { get; set; }

    [BindProperty]
    public InputModel Input { get; set; }

    public class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Birth Date")]
        [DataType(DataType.Date)]
        public DateTime DOB { get; set; }

        [Phone]
        [Display(Name = "Phone number")]
        public string PhoneNumber { get; set; }
    }

    private async Task LoadAsync(WebApp1User user)
    {
        var userName = await _userManager.GetUserNameAsync(user);
        var phoneNumber = await _userManager.GetPhoneNumberAsync(user);

        Username = userName;

        Input = new InputModel
        {
            Name = user.Name,
            DOB = user.DOB,
            PhoneNumber = phoneNumber
        };
    }

    public async Task<IActionResult> OnGetAsync()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }

        await LoadAsync(user);
        return Page();
    }

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

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

        if (Input.Name != user.Name)
        {
            user.Name = Input.Name;
        }

        if (Input.DOB != user.DOB)
        {
            user.DOB = Input.DOB;
        }

        await _userManager.UpdateAsync(user);
        await _signInManager.RefreshSignInAsync(user);
        StatusMessage = "Your profile has been updated";
        return RedirectToPage();
    }
}

Atualize o Areas/Identity/Pages/Account/Manage/Index.cshtml com a seguinte marcação destacada:

@page
@model IndexModel
@{
    ViewData["Title"] = "Profile";
    ViewData["ActivePage"] = ManageNavPages.Index;
}

<h3>@ViewData["Title"]</h3>
<partial name="_StatusMessage" for="StatusMessage" />
<div class="row">
    <div class="col-md-6">
        <form id="profile-form" method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-floating">
                <input asp-for="Username" class="form-control" disabled />
                <label asp-for="Username" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.Name" class="form-control" />
                <label asp-for="Input.Name" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.DOB" class="form-control" />
                <label asp-for="Input.DOB" class="form-label"></label>
            </div>
            <div class="form-floating">
                <input asp-for="Input.PhoneNumber" class="form-control" />
                <label asp-for="Input.PhoneNumber" class="form-label"></label>
                <span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
            </div>
            <button id="update-profile-button" type="submit" class="w-100 btn btn-lg btn-primary">Save</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Atualizar a página Account/Register.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Register.cshtml.cs com o seguinte código destacado:

    public class RegisterModel : PageModel
    {
        private readonly SignInManager<WebApp1User> _signInManager;
        private readonly UserManager<WebApp1User> _userManager;
        private readonly IUserStore<WebApp1User> _userStore;
        private readonly IUserEmailStore<WebApp1User> _emailStore;
        private readonly ILogger<RegisterModel> _logger;
        private readonly IEmailSender _emailSender;

        public RegisterModel(
            UserManager<WebApp1User> userManager,
            IUserStore<WebApp1User> userStore,
            SignInManager<WebApp1User> signInManager,
            ILogger<RegisterModel> logger,
            IEmailSender emailSender)
        {
            _userManager = userManager;
            _userStore = userStore;
            _emailStore = GetEmailStore();
            _signInManager = signInManager;
            _logger = logger;
            _emailSender = emailSender;
        }

        /// <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>
        [BindProperty]
        public InputModel Input { get; set; }

        // Remaining API warnings ommited.
        public string ReturnUrl { get; set; }

        public IList<AuthenticationScheme> ExternalLogins { get; set; }

        public class InputModel
        {
            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "Full name")]
            public string Name { get; set; }

            [Required]
            [Display(Name = "Birth Date")]
            [DataType(DataType.Date)]
            public DateTime DOB { get; set; }

            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }

            [Required]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }

            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }
        }


        public async Task OnGetAsync(string returnUrl = null)
        {
            ReturnUrl = returnUrl;
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        }

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl ??= Url.Content("~/");
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
            {
                var user = CreateUser();

                user.Name = Input.Name;
                user.DOB = Input.DOB;

                await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
                await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
                var result = await _userManager.CreateAsync(user, Input.Password);

                if (result.Succeeded)
                {
                    _logger.LogInformation("User created a new account with password.");

                    var userId = await _userManager.GetUserIdAsync(user);
                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                    var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                        protocol: Request.Scheme);

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

                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
                    {
                        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                    }
                    else
                    {
                        await _signInManager.SignInAsync(user, isPersistent: false);
                        return LocalRedirect(returnUrl);
                    }
                }
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError(string.Empty, error.Description);
                }
            }

            // If we got this far, something failed, redisplay form
            return Page();
        }

        private WebApp1User CreateUser()
        {
            try
            {
                return Activator.CreateInstance<WebApp1User>();
            }
            catch
            {
                throw new InvalidOperationException($"Can't create an instance of '{nameof(WebApp1User)}'. " +
                    $"Ensure that '{nameof(WebApp1User)}' is not an abstract class and has a parameterless constructor, or alternatively " +
                    $"override the register page in /Areas/Identity/Pages/Account/Register.cshtml");
            }
        }

        private IUserEmailStore<WebApp1User> GetEmailStore()
        {
            if (!_userManager.SupportsUserEmail)
            {
                throw new NotSupportedException("The default UI requires a user store with email support.");
            }
            return (IUserEmailStore<WebApp1User>)_userStore;
        }
    }
}

Atualize o Areas/Identity/Pages/Account/Register.cshtml com a seguinte marcação destacada:

@page
@model RegisterModel
@{
    ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>

<div class="row">
    <div class="col-md-4">
        <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.Name" class="form-control" />
                <label asp-for="Input.Name"></label>
                <span asp-validation-for="Input.Name" class="text-danger"></span>
            </div>
            <div class="form-floating">
                <input asp-for="Input.DOB" class="form-control" />
                <label asp-for="Input.DOB"></label>
                <span asp-validation-for="Input.DOB" 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>
            <div class="form-floating">
                <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" />
                <label asp-for="Input.Password"></label>
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-floating">
                <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" />
                <label asp-for="Input.ConfirmPassword"></label>
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
        </form>
    </div>
    <div class="col-md-6 col-md-offset-2">
        <section>
            <h3>Use another service to register.</h3>
            <hr />
            @{
                if ((Model.ExternalLogins?.Count ?? 0) == 0)
                {
                    <div>
                        <p>
                            There are no external authentication services configured. See this <a href="https://go.microsoft.com/fwlink/?LinkID=532715">article
                            about setting up this ASP.NET application to support logging in via external services</a>.
                        </p>
                    </div>
                }
                else
                {
                    <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                        <div>
                            <p>
                                @foreach (var provider in Model.ExternalLogins!)
                                {
                                    <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                                }
                            </p>
                        </div>
                    </form>
                }
            }
        </section>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Compile o projeto.

Atualizar o layout

Consulte as alterações de Layout para obter instruções para adicionar links de entrada e de saída a cada página.

Adicionar uma migração para os dados de usuário personalizados

Na Console do Gerenciador de Pacotes do Visual Studio Gerenciador de Pacotes:

Add-Migration CustomUserData
Update-Database

Testar criar, exibir, baixar, excluir dados de usuário personalizados

Teste o aplicativo:

  • Registre um novo usuário.
  • Exiba os dados personalizados do usuário na /Identity/Account/Manage página.
  • Baixe e exiba os dados pessoais dos usuários da /Identity/Account/Manage/PersonalData página.

SDK do .NET Core 3.0

Criar um Razor aplicativo Web

  • No menu Visual Studio File, selecione New>Project. Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download .
  • Selecione ASP.NET Core Aplicativo Web>OK
  • Selecione Aplicação Web>OK
  • Compile e execute o projeto.

Execute o scaffolder do Identity

  • Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto >Add>New Scaffolded Item.
  • No painel esquerdo da caixa de diálogo Adicionar Scaffold , selecione Identity>Adicionar.
  • Na caixa de diálogo Adicionar Identity, as seguintes opções:
    • Selecione o arquivo de layout existente ~/Pages/Shared/_Layout.cshtml
    • Selecione os seguintes arquivos para substituir:
      • Account/Register
      • Account/Manage/Index
    • Selecione o + botão para criar uma nova classe de contexto de dados. Aceite o tipo (WebApp1.Models.WebApp1Context se o projeto for denominado WebApp1).
    • Selecione o + botão para criar uma nova classe user. Aceite o tipo (WebApp1User se o projeto se chamar WebApp1) >Adicionar.
  • Selecione Adicionar.

Siga as instruções em Migrações, UseAuthentication e layout para executar as seguintes etapas:

  • Crie uma migração e atualize o banco de dados.
  • Adicione UseAuthentication a Startup.Configure.
  • Adicione <partial name="_LoginPartial" /> ao arquivo de layout.
  • Teste o aplicativo:
    • Registrar um usuário
    • Selecione o novo nome de usuário (ao lado do link logoff ). Talvez seja necessário expandir a janela ou selecionar o ícone da barra de navegação para mostrar o nome de usuário e outros links.
    • Selecione a guia Dados Pessoais .
    • Selecione o botão Baixar e examine o PersonalData.json arquivo.
    • Teste o botão Excluir , que exclui o usuário conectado.

Adicionar dados de usuário personalizados ao BD Identity

Atualize a IdentityUser classe derivada com propriedades personalizadas. Se você nomeou o projeto WebApp1, o arquivo será nomeado Areas/Identity/Data/WebApp1User.cs. Atualize o arquivo com o seguinte código:

using System;
using Microsoft.AspNetCore.Identity;

namespace WebApp1.Areas.Identity.Data
{
    public class WebApp1User : IdentityUser
    {
        [PersonalData]
        public string Name { get; set; }
        [PersonalData]
        public DateTime DOB { get; set; }
    }
}

As propriedades com o atributo PersonalData são:

  • Excluído quando o Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtmlRazor Page chama UserManager.Delete.
  • Incluído nos dados baixados pelo Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtmlRazor Page.

Atualizar a página Conta/Gerenciar/Index.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Manage/Index.cshtml.cs com o seguinte código destacado:

public partial class IndexModel : PageModel
{
    private readonly UserManager<WebApp1User> _userManager;
    private readonly SignInManager<WebApp1User> _signInManager;

    public IndexModel(
        UserManager<WebApp1User> userManager,
        SignInManager<WebApp1User> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    public string Username { get; set; }

    [TempData]
    public string StatusMessage { get; set; }

    [BindProperty]
    public InputModel Input { get; set; }

    public class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Birth Date")]
        [DataType(DataType.Date)]
        public DateTime DOB { get; set; }

        [Phone]
        [Display(Name = "Phone number")]
        public string PhoneNumber { get; set; }
    }

    private async Task LoadAsync(WebApp1User user)
    {
        var userName = await _userManager.GetUserNameAsync(user);
        var phoneNumber = await _userManager.GetPhoneNumberAsync(user);

        Username = userName;

        Input = new InputModel
        {
            Name = user.Name,
            DOB = user.DOB,
            PhoneNumber = phoneNumber
        };
    }

    public async Task<IActionResult> OnGetAsync()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound(
                $"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }

        await LoadAsync(user);
        return Page();
    }

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

        var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
        if (Input.PhoneNumber != phoneNumber)
        {
            var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, 
                Input.PhoneNumber);

            if (!setPhoneResult.Succeeded)
            {
                var userId = await _userManager.GetUserIdAsync(user);
                throw new InvalidOperationException(
                    $"Unexpected error occurred setting phone number for user with ID '{userId}'.");
            }
        }
        
        if (Input.Name != user.Name)
        {
            user.Name = Input.Name;
        }

        if (Input.DOB != user.DOB)
        {
            user.DOB = Input.DOB;
        }

        await _userManager.UpdateAsync(user);

        await _signInManager.RefreshSignInAsync(user);
        StatusMessage = "Your profile has been updated";
        return RedirectToPage();
    }
}

Atualize o Areas/Identity/Pages/Account/Manage/Index.cshtml com a seguinte marcação destacada:

@page
@model IndexModel
@{
    ViewData["Title"] = "Profile";
    ViewData["ActivePage"] = ManageNavPages.Index;
}

<h4>@ViewData["Title"]</h4>
<partial name="_StatusMessage" model="Model.StatusMessage" />
<div class="row">
    <div class="col-md-6">
        <form id="profile-form" method="post">
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Username"></label>
                <input asp-for="Username" class="form-control" disabled />
            </div>
            <div class="form-group">
                <label asp-for="Input.Name"></label>
                <input asp-for="Input.Name" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="Input.DOB"></label>
                <input asp-for="Input.DOB" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="Input.PhoneNumber"></label>
                <input asp-for="Input.PhoneNumber" class="form-control" />
                <span asp-validation-for="Input.PhoneNumber" 
                    class="text-danger"></span>
            </div>
            <button id="update-profile-button" type="submit" 
                class="btn btn-primary">Save</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Atualizar a página Account/Register.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Register.cshtml.cs com o seguinte código destacado:

[AllowAnonymous]
public class RegisterModel : PageModel
{
    private readonly SignInManager<WebApp1User> _signInManager;
    private readonly UserManager<WebApp1User> _userManager;
    private readonly ILogger<RegisterModel> _logger;
    private readonly IEmailSender _emailSender;

    public RegisterModel(
        UserManager<WebApp1User> userManager,
        SignInManager<WebApp1User> signInManager,
        ILogger<RegisterModel> logger,
        IEmailSender emailSender)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _logger = logger;
        _emailSender = emailSender;
    }

    [BindProperty]
    public InputModel Input { get; set; }

    public string ReturnUrl { get; set; }

    public IList<AuthenticationScheme> ExternalLogins { get; set; }

    public class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Birth Date")]
        [DataType(DataType.Date)]
        public DateTime DOB { get; set; }

        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

    public async Task OnGetAsync(string returnUrl = null)
    {
        ReturnUrl = returnUrl;
        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
    }

    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        if (ModelState.IsValid)
        {
            var user = new WebApp1User {
                Name = Input.Name,
                DOB = Input.DOB,
                UserName = Input.Email, 
                Email = Input.Email 
            };
            var result = await _userManager.CreateAsync(user, Input.Password);
            if (result.Succeeded)
            {
                _logger.LogInformation("User created a new account with password.");

                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { area = "Identity", userId = user.Id, code = code },
                    protocol: Request.Scheme);

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

                if (_userManager.Options.SignIn.RequireConfirmedAccount)
                {
                    return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
                }
                else
                {
                    await _signInManager.SignInAsync(user, isPersistent: false);
                    return LocalRedirect(returnUrl);
                }
            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }

        // If we got this far, something failed, redisplay form
        return Page();
    }
}

Atualize o Areas/Identity/Pages/Account/Register.cshtml com a seguinte marcação destacada:

@page
@model RegisterModel
@{
    ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>

<div class="row">
    <div class="col-md-4">
        <form asp-route-returnUrl="@Model.ReturnUrl" method="post">
            <h4>Create a new account.</h4>
            <hr />
            <div asp-validation-summary="All" class="text-danger"></div>

            <div class="form-group">
                <label asp-for="Input.Name"></label>
                <input asp-for="Input.Name" class="form-control" />
                <span asp-validation-for="Input.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.DOB"></label>
                <input asp-for="Input.DOB" class="form-control" />
                <span asp-validation-for="Input.DOB" class="text-danger"></span>
            </div>
            
            <div class="form-group">
                <label asp-for="Input.Email"></label>
                <input asp-for="Input.Email" class="form-control" />
                <span asp-validation-for="Input.Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.Password"></label>
                <input asp-for="Input.Password" class="form-control" />
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.ConfirmPassword"></label>
                <input asp-for="Input.ConfirmPassword" class="form-control" />
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Register</button>
        </form>
    </div>
    <div class="col-md-6 col-md-offset-2">
        <section>
            <h4>Use another service to register.</h4>
            <hr />
            @{
                if ((Model.ExternalLogins?.Count ?? 0) == 0)
                {
                    <div>
                        <p>
                            There are no external authentication services configured. See 
                             <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
                            for details on setting up this ASP.NET application to support 
                            logging in via external services.
                        </p>
                    </div>
                }
                else
                {
                    <form id="external-account" asp-page="./ExternalLogin" 
                        asp-route-returnUrl="@Model.ReturnUrl" method="post" 
                        class="form-horizontal">
                        <div>
                            <p>
                                @foreach (var provider in Model.ExternalLogins)
                                {
                                    <button type="submit" class="btn btn-primary" name="provider" 
                                        value="@provider.Name" 
                                        title="Log in using your @provider.DisplayName account">
                                            @provider.DisplayName</button>
                                }
                            </p>
                        </div>
                    </form>
                }
            }
        </section>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Compile o projeto.

Adicionar uma migração para os dados de usuário personalizados

Na Console do Gerenciador de Pacotes do Visual Studio Gerenciador de Pacotes:

Add-Migration CustomUserData
Update-Database

Testar criar, exibir, baixar, excluir dados de usuário personalizados

Teste o aplicativo:

  • Registre um novo usuário.
  • Exiba os dados personalizados do usuário na /Identity/Account/Manage página.
  • Baixe e exiba os dados pessoais dos usuários da /Identity/Account/Manage/PersonalData página.

Adicionar declarações ao Identity usando IUserClaimsPrincipalFactory<ApplicationUser>

Note

Esta seção não é uma extensão do tutorial anterior. Para aplicar as seguintes etapas ao aplicativo criado usando o tutorial, consulte este problema do GitHub.

Declarações adicionais podem ser adicionadas a ASP.NET Core Identity usando a interface IUserClaimsPrincipalFactory<T>. Essa classe pode ser adicionada ao aplicativo no Startup.ConfigureServices método. Adicione a implementação personalizada da classe da seguinte maneira:

public void ConfigureServices(IServiceCollection services)
{
    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, 
        AdditionalUserClaimsPrincipalFactory>();

O código de demonstração usa a ApplicationUser classe. Essa classe adiciona uma IsAdmin propriedade que é usada para adicionar a declaração adicional.

public class ApplicationUser : IdentityUser
{
    public bool IsAdmin { get; set; }
}

O AdditionalUserClaimsPrincipalFactory implementa a interface UserClaimsPrincipalFactory. Uma nova declaração de função é adicionada ao ClaimsPrincipal.

public class AdditionalUserClaimsPrincipalFactory 
        : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
    public AdditionalUserClaimsPrincipalFactory( 
        UserManager<ApplicationUser> userManager,
        RoleManager<IdentityRole> roleManager, 
        IOptions<IdentityOptions> optionsAccessor) 
        : base(userManager, roleManager, optionsAccessor)
    {}

    public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
    {
        var principal = await base.CreateAsync(user);
        var identity = (ClaimsIdentity)principal.Identity;

        var claims = new List<Claim>();
        if (user.IsAdmin)
        {
            claims.Add(new Claim(JwtClaimTypes.Role, "admin"));
        }
        else
        {
            claims.Add(new Claim(JwtClaimTypes.Role, "user"));
        }

        identity.AddClaims(claims);
        return principal;
    }
}

A declaração adicional pode ser usada no aplicativo. Em um Razor Page, a instância IAuthorizationService pode ser usada para acessar o valor da declaração.

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

@if ((await AuthorizationService.AuthorizeAsync(User, "IsAdmin")).Succeeded)
{
    <ul class="mr-auto navbar-nav">
        <li class="nav-item">
            <a class="nav-link" asp-controller="Admin" asp-action="Index">ADMIN</a>
        </li>
    </ul>
}

.NET Core 2.2 ou posterior SDK

Criar um Razor aplicativo Web

  • No menu Visual Studio File, selecione New>Project. Nomeie o projeto WebApp1 se desejar que ele corresponda ao namespace do código de exemplo de download .
  • Selecione ASP.NET Core Aplicativo Web>OK
  • Selecione ASP.NET Core 2.2 na lista suspensa
  • Selecione Aplicação Web>OK
  • Compile e execute o projeto.

Execute o scaffolder do Identity

  • Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto >Add>New Scaffolded Item.
  • No painel esquerdo da caixa de diálogo Adicionar Scaffold , selecione Identity>Adicionar.
  • Na caixa de diálogo Adicionar Identity, as seguintes opções:
    • Selecione o arquivo de layout existente ~/Pages/Shared/_Layout.cshtml
    • Selecione os seguintes arquivos para substituir:
      • Account/Register
      • Account/Manage/Index
    • Selecione o + botão para criar uma nova classe de contexto de dados. Aceite o tipo (WebApp1.Models.WebApp1Context se o projeto for denominado WebApp1).
    • Selecione o + botão para criar uma nova classe user. Aceite o tipo (WebApp1User se o projeto se chamar WebApp1) >Adicionar.
  • Selecione Adicionar.

Siga as instruções em Migrações, UseAuthentication e layout para executar as seguintes etapas:

  • Crie uma migração e atualize o banco de dados.
  • Adicione UseAuthentication a Startup.Configure.
  • Adicione <partial name="_LoginPartial" /> ao arquivo de layout.
  • Teste o aplicativo:
    • Registrar um usuário
    • Selecione o novo nome de usuário (ao lado do link logoff ). Talvez seja necessário expandir a janela ou selecionar o ícone da barra de navegação para mostrar o nome de usuário e outros links.
    • Selecione a guia Dados Pessoais .
    • Selecione o botão Baixar e examine o PersonalData.json arquivo.
    • Teste o botão Excluir , que exclui o usuário conectado.

Adicionar dados de usuário personalizados ao BD Identity

Atualize a IdentityUser classe derivada com propriedades personalizadas. Se você nomeou o projeto WebApp1, o arquivo será nomeado Areas/Identity/Data/WebApp1User.cs. Atualize o arquivo com o seguinte código:

using Microsoft.AspNetCore.Identity;
using System;

namespace WebApp1.Areas.Identity.Data
{
    public class WebApp1User : IdentityUser
    {
        [PersonalData]
        public string Name { get; set; }
        [PersonalData]
        public DateTime DOB { get; set; }
    }
}

As propriedades com o atributo PersonalData são:

  • Excluído quando o Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtmlRazor Page chama UserManager.Delete.
  • Incluído nos dados baixados pelo Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtmlRazor Page.

Atualizar a página Conta/Gerenciar/Index.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Manage/Index.cshtml.cs com o seguinte código destacado:

public partial class IndexModel : PageModel
{
    private readonly UserManager<WebApp1User> _userManager;
    private readonly SignInManager<WebApp1User> _signInManager;
    private readonly IEmailSender _emailSender;

    public IndexModel(
        UserManager<WebApp1User> userManager,
        SignInManager<WebApp1User> signInManager,
        IEmailSender emailSender)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _emailSender = emailSender;
    }

    public string Username { get; set; }
    public bool IsEmailConfirmed { get; set; }

    [TempData]
    public string StatusMessage { get; set; }

    [BindProperty]
    public InputModel Input { get; set; }

    public class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Birth Date")]
        [DataType(DataType.Date)]
        public DateTime DOB { get; set; }

        [Required]
        [EmailAddress]
        public string Email { get; set; }

        [Phone]
        [Display(Name = "Phone number")]
        public string PhoneNumber { get; set; }
    }

    public async Task<IActionResult> OnGetAsync()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }

        var userName = await _userManager.GetUserNameAsync(user);
        var email = await _userManager.GetEmailAsync(user);
        var phoneNumber = await _userManager.GetPhoneNumberAsync(user);

        Username = userName;

        Input = new InputModel
        {
            Name = user.Name,
            DOB = user.DOB,
            Email = email,
            PhoneNumber = phoneNumber
        };

        IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);

        return Page();
    }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }

        var email = await _userManager.GetEmailAsync(user);
        if (Input.Email != email)
        {
            var setEmailResult = await _userManager.SetEmailAsync(user, Input.Email);
            if (!setEmailResult.Succeeded)
            {
                var userId = await _userManager.GetUserIdAsync(user);
                throw new InvalidOperationException($"Unexpected error occurred setting email for user with ID '{userId}'.");
            }
        }

        if (Input.Name != user.Name)
        {
            user.Name = Input.Name;
        }

        if (Input.DOB != user.DOB)
        {
            user.DOB = Input.DOB;
        }

        var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
        if (Input.PhoneNumber != phoneNumber)
        {
            var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
            if (!setPhoneResult.Succeeded)
            {
                var userId = await _userManager.GetUserIdAsync(user);
                throw new InvalidOperationException($"Unexpected error occurred setting phone number for user with ID '{userId}'.");
            }
        }

        await _userManager.UpdateAsync(user);

        await _signInManager.RefreshSignInAsync(user);
        StatusMessage = "Your profile has been updated";
        return RedirectToPage();
    }

    public async Task<IActionResult> OnPostSendVerificationEmailAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        var user = await _userManager.GetUserAsync(User);
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }


        var userId = await _userManager.GetUserIdAsync(user);
        var email = await _userManager.GetEmailAsync(user);
        var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
        var callbackUrl = Url.Page(
            "/Account/ConfirmEmail",
            pageHandler: null,
            values: new { userId = userId, code = code },
            protocol: Request.Scheme);
        await _emailSender.SendEmailAsync(
            email,
            "Confirm your email",
            $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

        StatusMessage = "Verification email sent. Please check your email.";
        return RedirectToPage();
    }
}

Atualize o Areas/Identity/Pages/Account/Manage/Index.cshtml com a seguinte marcação destacada:

@page
@model IndexModel
@{
    ViewData["Title"] = "Profile";
    ViewData["ActivePage"] = ManageNavPages.Index;
}

<h4>@ViewData["Title"]</h4>
<partial name="_StatusMessage" for="StatusMessage" />
<div class="row">
    <div class="col-md-6">
        <form id="profile-form" method="post">
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Username"></label>
                <input asp-for="Username" class="form-control" disabled />
            </div>
            <div class="form-group">
                <label asp-for="Input.Email"></label>
                @if (Model.IsEmailConfirmed)
                {
                    <div class="input-group">
                        <input asp-for="Input.Email" class="form-control" />
                        <span class="input-group-addon" aria-hidden="true"><span class="glyphicon glyphicon-ok text-success"></span></span>
                    </div>
                }
                else
                {
                    <input asp-for="Input.Email" class="form-control" />
                    <button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" class="btn btn-link">Send verification email</button>
                }
                <span asp-validation-for="Input.Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.Name"></label>
                <input asp-for="Input.Name" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="Input.DOB"></label>
                <input asp-for="Input.DOB" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="Input.PhoneNumber"></label>
                <input asp-for="Input.PhoneNumber" class="form-control" />
                <span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
            </div>
            <button id="update-profile-button" type="submit" class="btn btn-primary">Save</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Atualizar a página Account/Register.cshtml

Atualize o InputModel no Areas/Identity/Pages/Account/Register.cshtml.cs com o seguinte código destacado:

[AllowAnonymous]
public class RegisterModel : PageModel
{
    private readonly SignInManager<WebApp1User> _signInManager;
    private readonly UserManager<WebApp1User> _userManager;
    private readonly ILogger<RegisterModel> _logger;
    private readonly IEmailSender _emailSender;

    public RegisterModel(
        UserManager<WebApp1User> userManager,
        SignInManager<WebApp1User> signInManager,
        ILogger<RegisterModel> logger,
        IEmailSender emailSender)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _logger = logger;
        _emailSender = emailSender;
    }

    [BindProperty]
    public InputModel Input { get; set; }

    public string ReturnUrl { get; set; }

    public class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Birth Date")]
        [DataType(DataType.Date)]
        public DateTime DOB { get; set; }

        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

    public void OnGet(string returnUrl = null)
    {
        ReturnUrl = returnUrl;
    }

    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        if (ModelState.IsValid)
        {
            var user = new WebApp1User {
                Name = Input.Name,
                DOB = Input.DOB,
                UserName = Input.Email,
                Email = Input.Email
            };
            var result = await _userManager.CreateAsync(user, Input.Password);
            if (result.Succeeded)
            {
                _logger.LogInformation("User created a new account with password.");

                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { userId = user.Id, code = code },
                    protocol: Request.Scheme);

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

                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }

        // If we got this far, something failed, redisplay form
        return Page();
    }
}

Atualize o Areas/Identity/Pages/Account/Register.cshtml com a seguinte marcação destacada:

@page
@model RegisterModel
@{
    ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>

<div class="row">
    <div class="col-md-4">
        <form asp-route-returnUrl="@Model.ReturnUrl" method="post">
            <h4>Create a new account.</h4>
            <hr />
            <div asp-validation-summary="All" class="text-danger"></div>

            <div class="form-group">
                <label asp-for="Input.Name"></label>
                <input asp-for="Input.Name" class="form-control" />
                <span asp-validation-for="Input.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.DOB"></label>
                <input asp-for="Input.DOB" class="form-control" />
                <span asp-validation-for="Input.DOB" class="text-danger"></span>
            </div>

            <div class="form-group">
                <label asp-for="Input.Email"></label>
                <input asp-for="Input.Email" class="form-control" />
                <span asp-validation-for="Input.Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.Password"></label>
                <input asp-for="Input.Password" class="form-control" />
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.ConfirmPassword"></label>
                <input asp-for="Input.ConfirmPassword" class="form-control" />
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Register</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Compile o projeto.

Adicionar uma migração para os dados de usuário personalizados

As propriedades personalizadas adicionadas à WebApp1UserIdentity classe de usuário precisam ser refletidas no banco de dados. Uma migração agora é necessária para gerar o SQL necessário para adicionar as novas colunas e, em seguida, o banco de dados precisa ser atualizado para aplicar essas alterações.

O scaffolder Identity criou um DbContext (WebApp1Context) junto com ApplicationDbContext original do modelo de projeto. Você deve especificar o novo WebApp1ContextIdentityDbContext a ser usado ao executar comandos de migração.

Na Console do Gerenciador de Pacotes do Visual Studio Gerenciador de Pacotes:

Add-Migration CustomUserData -Context WebApp1Context
Update-Database -Context WebApp1Context

Testar criar, exibir, baixar, excluir dados de usuário personalizados

Teste o aplicativo:

  • Registre um novo usuário.
  • Exiba os dados personalizados do usuário na /Identity/Account/Manage página.
  • Baixe e exiba os dados pessoais dos usuários da /Identity/Account/Manage/PersonalData página.