Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln visar hur du:
- Lägg till anpassade användardata i en ASP.NET Core-webbapp.
- Markera den anpassade användardatamodellen med PersonalDataAttribute attributet så att den automatiskt är tillgänglig för nedladdning och borttagning. Om du gör så att data kan laddas ned och tas bort uppfyller du GDPR-kraven .
Projektexemplet skapas från en Razor Pages-webbapp, men anvisningarna är liknande för en ASP.NET Core MVC-webbapp.
Visa eller ladda ned exempelkod (hur du laddar ned)
Förutsättningar
Skapa en Razor webbapp
- Välj Nytt> på Menyn Visual Studio-fil. Ge projektet namnet WebApp1 om du vill att det ska matcha namnområdet för nedladdningsexempelkoden .
- Välj ASP.NET Core Web Application>OK
- Välj Webbprogram>OK
- Skapa och kör projektet.
Identity Kör byggnadsställningen
- Från Solution Explorer högerklickar du på projektet >Lägg till>nytt skrafferat objekt.
- I den vänstra rutan i dialogrutan Lägg till byggnadsställning väljer du Identity>Lägg till.
- I dialogrutan Lägg till Identity finns följande alternativ:
- Välj den befintliga layoutfilen
~/Pages/Shared/_Layout.cshtml
- Välj följande filer att åsidosätta:
- Konto/registrera
- Konto/Hantera/Index
- + Välj knappen för att skapa en ny datakontextklass. Acceptera typen (WebApp1.Models.WebApp1Context om projektet heter WebApp1).
- + Välj knappen för att skapa en ny användarklass. Acceptera typen (WebApp1User om projektet heter WebApp1) >Lägg till.
- Välj den befintliga layoutfilen
- Välj Lägg till.
Följ anvisningarna i Migreringar, UseAuthentication och layout för att utföra följande steg:
- Skapa en migrering och uppdatera databasen.
- Lägg till
UseAuthentication
iProgram.cs
- Lägg till
<partial name="_LoginPartial" />
i layoutfilen. - Testa appen:
- Registrera en användare
- Välj det nya användarnamnet (bredvid länken Logga ut ). Du kan behöva expandera fönstret eller välja navigeringsfältikonen för att visa användarnamnet och andra länkar.
- Välj fliken Personliga data .
- Välj knappen Ladda ned och undersökte
PersonalData.json
filen. - Testa knappen Ta bort , som tar bort den inloggade användaren.
Lägga till anpassade användardata i Identity databasen
Uppdatera den IdentityUser
härledda klassen med anpassade egenskaper. Om du gav projektet namnet WebApp1 får filen namnet Areas/Identity/Data/WebApp1User.cs
. Uppdatera filen med följande kod:
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; }
}
Egenskaper med attributet PersonalData är:
- Tas bort när sidan
Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml
Razor anroparUserManager.Delete
. - Ingår i de nedladdade data från sidan
Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml
Razor .
Uppdatera sidan Account/Manage/Index.cshtml
Uppdatera InputModel
i Areas/Identity/Pages/Account/Manage/Index.cshtml.cs
med följande markerade kod:
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();
}
}
Areas/Identity/Pages/Account/Manage/Index.cshtml
Uppdatera med följande markerade markeringar:
@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" />
}
Uppdatera sidan Account/Register.cshtml
Uppdatera InputModel
i Areas/Identity/Pages/Account/Register.cshtml.cs
med följande markerade kod:
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;
}
}
}
Areas/Identity/Pages/Account/Register.cshtml
Uppdatera med följande markerade markeringar:
@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" />
}
Skapa projektet.
Uppdatera layouten
Se Layoutändringar för instruktioner för att lägga till inloggnings- och utloggningslänkar på varje sida.
Lägga till en migrering för anpassade användardata
I Visual Studio Package Manager-Konsol:
Add-Migration CustomUserData
Update-Database
Testa skapa, visa, ladda ned, ta bort anpassade användardata
Testa appen:
- Registrera en ny användare.
- Visa anpassade användardata på
/Identity/Account/Manage
sidan. - Ladda ned och visa användarnas personliga data från
/Identity/Account/Manage/PersonalData
sidan.
Skapa en Razor webbapp
- Välj Nytt> på Menyn Visual Studio-fil. Ge projektet namnet WebApp1 om du vill att det ska matcha namnområdet för nedladdningsexempelkoden .
- Välj ASP.NET Core Web Application>OK
- Välj Webbprogram>OK
- Skapa och kör projektet.
Identity Kör byggnadsställningen
- Från Solution Explorer högerklickar du på projektet >Lägg till>nytt skrafferat objekt.
- I den vänstra rutan i dialogrutan Lägg till byggnadsställning väljer du Identity>Lägg till.
- I dialogrutan Lägg till Identity finns följande alternativ:
- Välj den befintliga layoutfilen
~/Pages/Shared/_Layout.cshtml
- Välj följande filer att åsidosätta:
- Konto/registrera
- Konto/Hantera/Index
- + Välj knappen för att skapa en ny datakontextklass. Acceptera typen (WebApp1.Models.WebApp1Context om projektet heter WebApp1).
- + Välj knappen för att skapa en ny användarklass. Acceptera typen (WebApp1User om projektet heter WebApp1) >Lägg till.
- Välj den befintliga layoutfilen
- Välj Lägg till.
Följ anvisningarna i Migreringar, UseAuthentication och layout för att utföra följande steg:
- Skapa en migrering och uppdatera databasen.
- Lägg till
UseAuthentication
iStartup.Configure
. - Lägg till
<partial name="_LoginPartial" />
i layoutfilen. - Testa appen:
- Registrera en användare
- Välj det nya användarnamnet (bredvid länken Logga ut ). Du kan behöva expandera fönstret eller välja navigeringsfältikonen för att visa användarnamnet och andra länkar.
- Välj fliken Personliga data .
- Välj knappen Ladda ned och undersökte
PersonalData.json
filen. - Testa knappen Ta bort , som tar bort den inloggade användaren.
Lägga till anpassade användardata i Identity databasen
Uppdatera den IdentityUser
härledda klassen med anpassade egenskaper. Om du gav projektet namnet WebApp1 får filen namnet Areas/Identity/Data/WebApp1User.cs
. Uppdatera filen med följande kod:
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; }
}
}
Egenskaper med attributet PersonalData är:
- Tas bort när sidan
Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml
Razor anroparUserManager.Delete
. - Ingår i de nedladdade data från sidan
Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml
Razor .
Uppdatera sidan Konto/Hantera/Index.cshtml
Uppdatera InputModel
i Areas/Identity/Pages/Account/Manage/Index.cshtml.cs
med följande markerade kod:
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();
}
}
Areas/Identity/Pages/Account/Manage/Index.cshtml
Uppdatera med följande markerade markeringar:
@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" />
}
Uppdatera sidan Account/Register.cshtml
Uppdatera InputModel
i Areas/Identity/Pages/Account/Register.cshtml.cs
med följande markerade kod:
[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();
}
}
Areas/Identity/Pages/Account/Register.cshtml
Uppdatera med följande markerade markeringar:
@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" />
}
Skapa projektet.
Lägga till en migrering för anpassade användardata
I Visual Studio Package Manager-Konsol:
Add-Migration CustomUserData
Update-Database
Testa skapa, visa, ladda ned, ta bort anpassade användardata
Testa appen:
- Registrera en ny användare.
- Visa anpassade användardata på
/Identity/Account/Manage
sidan. - Ladda ned och visa användarnas personliga data från
/Identity/Account/Manage/PersonalData
sidan.
Lägg till anspråk i Identity med hjälp av IUserClaimsPrincipalFactory<ApplicationUser>
Anmärkning
Denna sektion är inte ett tillägg till den föregående handledningen. Om du vill tillämpa följande steg på appen som skapats med hjälp av handledningen kan du läsa det här GitHub-ärendet.
Ytterligare krav kan läggas till i ASP.NET Core Identity genom att använda IUserClaimsPrincipalFactory<T>
-gränssnittet. Den här klassen kan läggas till i appen i Startup.ConfigureServices
-metoden. Lägg till den anpassade implementeringen av klassen på följande sätt:
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>,
AdditionalUserClaimsPrincipalFactory>();
Demokoden använder ApplicationUser
klassen. Den här klassen lägger till en IsAdmin
egenskap som används för att lägga till ytterligare anspråk.
public class ApplicationUser : IdentityUser
{
public bool IsAdmin { get; set; }
}
AdditionalUserClaimsPrincipalFactory
implementerar UserClaimsPrincipalFactory
gränssnittet. Ett nytt rollkrav läggs till i 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;
}
}
Det ytterligare anspråket kan sedan användas i appen. På en Razor sida kan instansen IAuthorizationService
användas för att komma åt anspråksvärdet.
@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 eller senare SDK
Skapa en Razor webbapp
- Välj Nytt> på Menyn Visual Studio-fil. Ge projektet namnet WebApp1 om du vill att det ska matcha namnområdet för nedladdningsexempelkoden .
- Välj ASP.NET Core Web Application>OK
- Välj ASP.NET Core 2.2 i listrutan
- Välj Webbprogram>OK
- Skapa och kör projektet.
Identity Kör byggnadsställningen
- Från Solution Explorer högerklickar du på projektet >Lägg till>nytt skrafferat objekt.
- I den vänstra rutan i dialogrutan Lägg till byggnadsställning väljer du Identity>Lägg till.
- I dialogrutan Lägg till Identity finns följande alternativ:
- Välj den befintliga layoutfilen
~/Pages/Shared/_Layout.cshtml
- Välj följande filer att åsidosätta:
- Konto/registrera
- Konto/Hantera/Index
- + Välj knappen för att skapa en ny datakontextklass. Acceptera typen (WebApp1.Models.WebApp1Context om projektet heter WebApp1).
- + Välj knappen för att skapa en ny användarklass. Acceptera typen (WebApp1User om projektet heter WebApp1) >Lägg till.
- Välj den befintliga layoutfilen
- Välj Lägg till.
Följ anvisningarna i Migreringar, UseAuthentication och layout för att utföra följande steg:
- Skapa en migrering och uppdatera databasen.
- Lägg till
UseAuthentication
iStartup.Configure
. - Lägg till
<partial name="_LoginPartial" />
i layoutfilen. - Testa appen:
- Registrera en användare
- Välj det nya användarnamnet (bredvid länken Logga ut ). Du kan behöva expandera fönstret eller välja navigeringsfältikonen för att visa användarnamnet och andra länkar.
- Välj fliken Personliga data .
- Välj knappen Ladda ned och undersökte
PersonalData.json
filen. - Testa knappen Ta bort , som tar bort den inloggade användaren.
Lägga till anpassade användardata i Identity databasen
Uppdatera den IdentityUser
härledda klassen med anpassade egenskaper. Om du gav projektet namnet WebApp1 får filen namnet Areas/Identity/Data/WebApp1User.cs
. Uppdatera filen med följande kod:
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; }
}
}
Egenskaper med attributet PersonalData är:
- Tas bort när sidan
Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml
Razor anroparUserManager.Delete
. - Ingår i de nedladdade data från sidan
Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml
Razor .
Uppdatera sidan Konto/Hantera/Index.cshtml
Uppdatera InputModel
i Areas/Identity/Pages/Account/Manage/Index.cshtml.cs
med följande markerade kod:
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();
}
}
Areas/Identity/Pages/Account/Manage/Index.cshtml
Uppdatera med följande markerade markeringar:
@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" />
}
Uppdatera sidan Account/Register.cshtml
Uppdatera InputModel
i Areas/Identity/Pages/Account/Register.cshtml.cs
med följande markerade kod:
[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();
}
}
Areas/Identity/Pages/Account/Register.cshtml
Uppdatera med följande markerade markeringar:
@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" />
}
Skapa projektet.
Lägga till en migrering för anpassade användardata
I Visual Studio Package Manager-Konsol:
Add-Migration CustomUserData
Update-Database
Testa skapa, visa, ladda ned, ta bort anpassade användardata
Testa appen:
- Registrera en ny användare.
- Visa anpassade användardata på
/Identity/Account/Manage
sidan. - Ladda ned och visa användarnas personliga data från
/Identity/Account/Manage/PersonalData
sidan.
ASP.NET Core