Dodawanie niestandardowych danych użytkownika do aplikacji internetowej platformy ASP.NET Core.
Oznacz niestandardowy model danych użytkownika za pomocą atrybutu PersonalDataAttribute , aby był on automatycznie dostępny do pobrania i usunięcia. Udostępnianie danych do pobrania i usunięcia pomaga spełnić wymagania RODO .
Przykładowy projekt jest tworzony na podstawie Razor aplikacji internetowej Pages, ale instrukcje są podobne dla aplikacji internetowej ASP.NET Core MVC.
W menu Plik programu Visual Studio wybierz pozycję Nowy>projekt. Nadaj projektowi nazwę WebApp1, jeśli chcesz go dopasować do przestrzeni nazw przykładowego kodu pobierania.
Domyślnie architektura plików binarnych platformy .NET do zainstalowania reprezentuje obecnie uruchomioną architekturę systemu operacyjnego. Aby określić inną architekturę systemu operacyjnego, zobacz dotnet tool install, --arch option(Instalacja narzędzia dotnet).
Aby uzyskać więcej informacji, zobacz problem z usługą GitHub dotnet/AspNetCore.Docs #29262.
Program PowerShell używa średnika jako separatora poleceń. W przypadku korzystania z programu PowerShell należy użyć średników na liście plików lub umieścić listę plików w podwójnych cudzysłowach.
Dodanie argumentu UseAuthentication do polecenia Program.cs
Dodaj <partial name="_LoginPartial" /> do pliku układu.
Przetestuj aplikację:
Rejestrowanie użytkownika
Wybierz nową nazwę użytkownika (obok linku Wyloguj). Może być konieczne rozwinięcie okna lub wybranie ikony paska nawigacyjnego, aby wyświetlić nazwę użytkownika i inne linki.
Wybierz kartę Dane osobowe.
Wybierz przycisk Pobierz i zbadaj PersonalData.json plik.
Przetestuj przycisk Usuń , który usuwa zalogowanego użytkownika.
Dodawanie niestandardowych danych użytkownika do Identity bazy danych
Zaktualizuj klasę pochodną IdentityUser za pomocą właściwości niestandardowych. Jeśli nazwano projekt WebApp1, plik ma nazwę Areas/Identity/Data/WebApp1User.cs. Zaktualizuj plik przy użyciu następującego kodu:
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; }
}
Usunięto, gdy strona wywołuje metodę Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtmlRazor UserManager.Delete.
Uwzględnione w pobranych danych przez Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtmlRazor stronę.
Account/Manage/Index.cshtml Aktualizowanie strony
Zaktualizuj element InputModel za Areas/Identity/Pages/Account/Manage/Index.cshtml.cs pomocą następującego wyróżnionego kodu:
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();
}
}
Zaktualizuj element Areas/Identity/Pages/Account/Manage/Index.cshtml za pomocą następującego wyróżnionego znacznika:
Zaktualizuj element InputModel za Areas/Identity/Pages/Account/Register.cshtml.cs pomocą następującego wyróżnionego kodu:
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;
}
}
}
Zaktualizuj element Areas/Identity/Pages/Account/Register.cshtml za pomocą następującego wyróżnionego znacznika:
@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" />
}
Skompiluj projekt.
Aktualizowanie układu
Zobacz Zmiany układu, aby uzyskać instrukcje dotyczące dodawania linków logowania i wylogowyń do każdej strony.
Dodawanie migracji dla niestandardowych danych użytkownika
W menu Plik programu Visual Studio wybierz pozycję Nowy>projekt. Nadaj projektowi nazwę WebApp1, jeśli chcesz go dopasować do przestrzeni nazw przykładowego kodu pobierania.
Domyślnie architektura plików binarnych platformy .NET do zainstalowania reprezentuje obecnie uruchomioną architekturę systemu operacyjnego. Aby określić inną architekturę systemu operacyjnego, zobacz dotnet tool install, --arch option(Instalacja narzędzia dotnet).
Aby uzyskać więcej informacji, zobacz problem z usługą GitHub dotnet/AspNetCore.Docs #29262.
Program PowerShell używa średnika jako separatora poleceń. W przypadku korzystania z programu PowerShell należy użyć średników na liście plików lub umieścić listę plików w podwójnych cudzysłowach.
Dodaj <partial name="_LoginPartial" /> do pliku układu.
Przetestuj aplikację:
Rejestrowanie użytkownika
Wybierz nową nazwę użytkownika (obok linku Wyloguj). Może być konieczne rozwinięcie okna lub wybranie ikony paska nawigacyjnego, aby wyświetlić nazwę użytkownika i inne linki.
Wybierz kartę Dane osobowe.
Wybierz przycisk Pobierz i zbadaj PersonalData.json plik.
Przetestuj przycisk Usuń , który usuwa zalogowanego użytkownika.
Dodawanie niestandardowych danych użytkownika do Identity bazy danych
Zaktualizuj klasę pochodną IdentityUser za pomocą właściwości niestandardowych. Jeśli nazwano projekt WebApp1, plik ma nazwę Areas/Identity/Data/WebApp1User.cs. Zaktualizuj plik przy użyciu następującego kodu:
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; }
}
}
W konsoli programu Visual Studio Menedżer pakietów:
Add-Migration CustomUserData
Update-Database
dotnet ef migrations add CustomUserData
dotnet ef database update
Testowanie tworzenia, wyświetlania, pobierania, usuwania niestandardowych danych użytkownika
Przetestuj aplikację:
Zarejestruj nowego użytkownika.
Wyświetl niestandardowe dane użytkownika na /Identity/Account/Manage stronie.
Pobierz i wyświetl dane osobowe użytkowników ze /Identity/Account/Manage/PersonalData strony.
Dodawanie oświadczeń do Identity użycia IUserClaimsPrincipalFactory<ApplicationUser>
Uwaga
Ta sekcja nie jest rozszerzeniem poprzedniego samouczka. Aby zastosować następujące kroki do aplikacji utworzonej przy użyciu samouczka, zobacz ten problem z usługą GitHub.
Dodatkowe oświadczenia można dodać do ASP.NET Core Identity przy użyciu interfejsu IUserClaimsPrincipalFactory<T> . Tę klasę można dodać do aplikacji w metodzie Startup.ConfigureServices . Dodaj niestandardową implementację klasy w następujący sposób:
Kod demonstracyjny ApplicationUser używa klasy . Ta klasa dodaje IsAdmin właściwość, która służy do dodawania dodatkowego oświadczenia.
public class ApplicationUser : IdentityUser
{
public bool IsAdmin { get; set; }
}
Element AdditionalUserClaimsPrincipalFactory implementuje UserClaimsPrincipalFactory interfejs. Nowe oświadczenie roli jest dodawane do elementu 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;
}
}
Następnie można użyć dodatkowego oświadczenia w aplikacji. Na stronie Razor IAuthorizationService wystąpienie może służyć do uzyskiwania dostępu do wartości oświadczenia.
W menu Plik programu Visual Studio wybierz pozycję Nowy>projekt. Nadaj projektowi nazwę WebApp1, jeśli chcesz go dopasować do przestrzeni nazw przykładowego kodu pobierania.
Domyślnie architektura plików binarnych platformy .NET do zainstalowania reprezentuje obecnie uruchomioną architekturę systemu operacyjnego. Aby określić inną architekturę systemu operacyjnego, zobacz dotnet tool install, --arch option(Instalacja narzędzia dotnet).
Aby uzyskać więcej informacji, zobacz problem z usługą GitHub dotnet/AspNetCore.Docs #29262.
Program PowerShell używa średnika jako separatora poleceń. W przypadku korzystania z programu PowerShell należy użyć średników na liście plików lub umieścić listę plików w podwójnych cudzysłowach.
Dodaj <partial name="_LoginPartial" /> do pliku układu.
Przetestuj aplikację:
Rejestrowanie użytkownika
Wybierz nową nazwę użytkownika (obok linku Wyloguj). Może być konieczne rozwinięcie okna lub wybranie ikony paska nawigacyjnego, aby wyświetlić nazwę użytkownika i inne linki.
Wybierz kartę Dane osobowe.
Wybierz przycisk Pobierz i zbadaj PersonalData.json plik.
Przetestuj przycisk Usuń , który usuwa zalogowanego użytkownika.
Dodawanie niestandardowych danych użytkownika do Identity bazy danych
Zaktualizuj klasę pochodną IdentityUser za pomocą właściwości niestandardowych. Jeśli nazwano projekt WebApp1, plik ma nazwę Areas/Identity/Data/WebApp1User.cs. Zaktualizuj plik przy użyciu następującego kodu:
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; }
}
}
W konsoli programu Visual Studio Menedżer pakietów:
Add-Migration CustomUserData
Update-Database
dotnet ef migrations add CustomUserData
dotnet ef database update
Testowanie tworzenia, wyświetlania, pobierania, usuwania niestandardowych danych użytkownika
Przetestuj aplikację:
Zarejestruj nowego użytkownika.
Wyświetl niestandardowe dane użytkownika na /Identity/Account/Manage stronie.
Pobierz i wyświetl dane osobowe użytkowników ze /Identity/Account/Manage/PersonalData strony.
Współpracuj z nami w serwisie GitHub
Źródło tej zawartości można znaleźć w witrynie GitHub, gdzie można również tworzyć i przeglądać problemy i żądania ściągnięcia. Więcej informacji znajdziesz w naszym przewodniku dla współtwórców.
Opinia o produkcie ASP.NET Core
ASP.NET Core to projekt typu open source. Wybierz link, aby przekazać opinię:
Zapoznaj się z wartościami domyślnymi ASP.NET Core Identity i dowiedz się, jak skonfigurować Identity właściwości do używania wartości niestandardowych.
Użyj Identity z aplikacją ASP.NET Core. Dowiedz się, jak ustawić wymagania dotyczące hasła (RequireDigit, RequiredLength, RequiredUniqueChars i nie tylko).