Adicionar, baixar e excluir dados de usuário personalizada à identidade em um projeto ASP.NET CoreAdd, download, and delete custom user data to Identity in an ASP.NET Core project

Por Rick AndersonBy Rick Anderson

Este artigo mostra como:This article shows how to:

  • Adicione dados de usuário personalizada para um aplicativo web ASP.NET Core.Add custom user data to an ASP.NET Core web app.
  • Decorar o modelo de dados de usuário personalizado PersonalDataAttribute com o atributo para que ele seja automaticamente disponibilizado para download e exclusão.Decorate the custom user data model with the PersonalDataAttribute attribute so it's automatically available for download and deletion. Tornando os dados capazes de ser baixado e excluído ajuda a cumprir GDPR requisitos.Making the data able to be downloaded and deleted helps meet GDPR requirements.

O exemplo de projeto é criado a partir de um aplicativo web páginas Razor, mas as instruções são semelhantes para um aplicativo web ASP.NET Core MVC.The project sample is created from a Razor Pages web app, but the instructions are similar for a ASP.NET Core MVC web app.

Exibir ou baixar código de exemplo (como baixar)View or download sample code (how to download)

Pré-requisitosPrerequisites

SDK do .NET core 2.2 ou posterior.NET Core 2.2 SDK or later

Criar um aplicativo Web do RazorCreate a Razor web app

  • No menu Arquivo do Visual Studio, selecione Novo > Projeto.From the Visual Studio File menu, select New > Project. Nomeie o projeto WebApp1 se você deseja corresponder ao namespace da baixar exemplo código.Name the project WebApp1 if you want to it match the namespace of the download sample code.
  • Selecione aplicativo Web ASP.NET Core > OkeySelect ASP.NET Core Web Application > OK
  • Selecione ASP.NET Core 2,2 na lista suspensaSelect ASP.NET Core 2.2 in the dropdown
  • Selecione aplicativo Web > OkeySelect Web Application > OK
  • Compile e execute o projeto.Build and run the project.

Execute o scaffolder de identidadeRun the Identity scaffolder

  • Partir Gerenciador de soluções, clique com botão direito no projeto > Add > New Scaffolded Item.From Solution Explorer, right-click on the project > Add > New Scaffolded Item.
  • No painel à esquerda do adicionar Scaffold caixa de diálogo, selecione identidade > adicionar.From the left pane of the Add Scaffold dialog, select Identity > ADD.
  • No identidade de adição caixa de diálogo, as seguintes opções:In the ADD Identity dialog, the following options:
    • Selecione o arquivo de layout existente ~/Pages/Shared/_Layout.cshtmlSelect the existing layout file ~/Pages/Shared/_Layout.cshtml
    • Selecione os arquivos a seguir para substituir:Select the following files to override:
      • Conta/registroAccount/Register
      • Conta/gerenciar/índiceAccount/Manage/Index
    • Selecione o + botão para criar um novo classe de contexto de dados.Select the + button to create a new Data context class. Aceite o tipo (WebApp1.Models.WebApp1Context se o projeto é denominado WebApp1).Accept the type (WebApp1.Models.WebApp1Context if the project is named WebApp1).
    • Selecione o + botão para criar um novo classe User.Select the + button to create a new User class. Aceite o tipo (WebApp1User se o projeto é denominado WebApp1) > adicionar.Accept the type (WebApp1User if the project is named WebApp1) > Add.
  • Selecione adicionar.Select ADD.

Siga as instruções da migrações, UseAuthentication e layout para executar as seguintes etapas:Follow the instruction in Migrations, UseAuthentication, and layout to perform the following steps:

  • Criar uma migração e atualizar o banco de dados.Create a migration and update the database.
  • Adicione UseAuthentication a Startup.Configure.Add UseAuthentication to Startup.Configure.
  • Adicionar <partial name="_LoginPartial" /> ao arquivo de layout.Add <partial name="_LoginPartial" /> to the layout file.
  • Teste o aplicativo:Test the app:
    • Registrar um usuárioRegister a user
    • Selecione o novo nome de usuário (ao lado de Logout link).Select the new user name (next to the Logout link). Talvez você precise expandir a janela ou selecione o ícone da barra de navegação para mostrar o nome de usuário e outros links.You might need to expand the window or select the navigation bar icon to show the user name and other links.
    • Selecione o dados pessoais guia.Select the Personal Data tab.
    • Selecione o Baixe botão e examinado o PersonalData.json arquivo.Select the Download button and examined the PersonalData.json file.
    • Teste o excluir botão, que exclui o fez logon de usuário.Test the Delete button, which deletes the logged on user.

Adicionar dados de usuário personalizada para o banco de dados de identidadeAdd custom user data to the Identity DB

Atualização de IdentityUser derivado da classe com propriedades personalizadas.Update the IdentityUser derived class with custom properties. Se você nomeou o projeto WebApp1, o arquivo é nomeado Areas/Identity/Data/WebApp1User.cs.If you named the project WebApp1, the file is named Areas/Identity/Data/WebApp1User.cs. Atualize o arquivo com o código a seguir:Update the file with the following code:

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 decoradas com o PersonalData atributo são:Properties decorated with the PersonalData attribute are:

  • Excluído, quando o Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml página do Razor chama UserManager.Delete.Deleted when the Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml Razor Page calls UserManager.Delete.
  • Incluído nos dados baixados pela Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml página do Razor.Included in the downloaded data by the Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml Razor Page.

Atualizar a página Account/Manage/Index.cshtmlUpdate the Account/Manage/Index.cshtml page

Atualizar o InputModel na Areas/Identity/Pages/Account/Manage/Index.cshtml.cs com o seguinte código realçado:Update the InputModel in Areas/Identity/Pages/Account/Manage/Index.cshtml.cs with the following highlighted code:

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

Atualizar o Areas/Identity/Pages/Account/Manage/Index.cshtml com a seguinte marcação realçada:Update the Areas/Identity/Pages/Account/Manage/Index.cshtml with the following highlighted markup:

@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">
                <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>
                <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 RegisterUpdate the Account/Register.cshtml page

Atualizar o InputModel na Areas/Identity/Pages/Account/Register.cshtml.cs com o seguinte código realçado:Update the InputModel in Areas/Identity/Pages/Account/Register.cshtml.cs with the following highlighted code:

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

Atualizar o Areas/Identity/Pages/Account/Register.cshtml com a seguinte marcação realçada:Update the Areas/Identity/Pages/Account/Register.cshtml with the following highlighted markup:

@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.Build the project.

Adicionar uma migração para os dados de usuário personalizadaAdd a migration for the custom user data

No Visual Studio Package Manager Console:In the Visual Studio Package Manager Console:

Add-Migration CustomUserData
Update-Database

Teste de criar, exibir, baixar, excluir dados de usuário personalizadaTest create, view, download, delete custom user data

Teste o aplicativo:Test the app:

  • Registre um novo usuário.Register a new user.
  • Exibir os dados de usuário personalizada no /Identity/Account/Manage página.View the custom user data on the /Identity/Account/Manage page.
  • Baixar e exibir os dados pessoais de usuários da /Identity/Account/Manage/PersonalData página.Download and view the users personal data from the /Identity/Account/Manage/PersonalData page.