diff --git a/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Manage/Index.cshtml b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Manage/Index.cshtml
new file mode 100644
index 0000000000..3f15aaca23
--- /dev/null
+++ b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Manage/Index.cshtml
@@ -0,0 +1,53 @@
+@page
+@model IndexModel
+@{
+ ViewData["Title"] = "Profile";
+}
+
+
@ViewData["Title"]
+@Html.Partial("_StatusMessage", Model.StatusMessage)
+
+
+@section Scripts {
+
+}
diff --git a/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs
new file mode 100644
index 0000000000..6ca6705ca5
--- /dev/null
+++ b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs
@@ -0,0 +1,164 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using IdentitySample.DefaultUI.Data;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Identity.UI.Services;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace IdentitySample.DefaultUI
+{
+ public class IndexModel : PageModel
+ {
+ private readonly UserManager _userManager;
+ private readonly SignInManager _signInManager;
+ private readonly IEmailSender _emailSender;
+
+ public IndexModel(
+ UserManager userManager,
+ SignInManager 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]
+ [EmailAddress]
+ public string Email { get; set; }
+
+ [Phone]
+ [Display(Name = "Phone number")]
+ public string PhoneNumber { get; set; }
+
+ [Required]
+ [DataType(DataType.Text)]
+ [Display(Name = "Full Name")]
+ public string Name { get; set; }
+
+ [Required]
+ [Range(0, 199, ErrorMessage = "Age must be between 0 and 199")]
+ [Display(Name = "Age")]
+ public int Age { get; set; }
+ }
+
+ public async Task OnGetAsync()
+ {
+ var user = await _userManager.GetUserAsync(User);
+ if (user == null)
+ {
+ return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
+ }
+
+ Username = user.UserName;
+ Input = new InputModel
+ {
+ Name = user.Name,
+ Age = user.Age,
+ Email = user.Email,
+ PhoneNumber = user.PhoneNumber
+ };
+
+ IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);
+
+ return Page();
+ }
+
+ public async Task 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)}'.");
+ }
+
+ if (Input.Name != user.Name)
+ {
+ user.Name = Input.Name;
+ }
+
+ if (Input.Age != user.Age)
+ {
+ user.Age = Input.Age;
+ }
+
+ var updateProfileResult = await _userManager.UpdateAsync(user);
+ if (!updateProfileResult.Succeeded)
+ {
+ throw new InvalidOperationException($"Unexpected error ocurred updating the profile for user with ID '{user.Id}'");
+ }
+
+ if (Input.Email != user.Email)
+ {
+ var setEmailResult = await _userManager.SetEmailAsync(user, Input.Email);
+ if (!setEmailResult.Succeeded)
+ {
+ throw new InvalidOperationException($"Unexpected error occurred setting email for user with ID '{user.Id}'.");
+ }
+ }
+
+ if (Input.PhoneNumber != user.PhoneNumber)
+ {
+ var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
+ if (!setPhoneResult.Succeeded)
+ {
+ throw new InvalidOperationException($"Unexpected error occurred setting phone number for user with ID '{user.Id}'.");
+ }
+ }
+
+ StatusMessage = "Your profile has been updated";
+ return RedirectToPage();
+ }
+
+ public async Task 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 code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
+ var callbackUrl = Url.Page(
+ "/Account/ConfirmEmail",
+ pageHandler: null,
+ values: new { user.Id, code },
+ protocol: Request.Scheme);
+ await _emailSender.SendEmailAsync(
+ user.Email,
+ "Confirm your email",
+ $"Please confirm your account by clicking here.");
+
+ StatusMessage = "Verification email sent. Please check your email.";
+ return RedirectToPage();
+ }
+ }
+}
diff --git a/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Register.cshtml b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Register.cshtml
new file mode 100644
index 0000000000..259373e966
--- /dev/null
+++ b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Register.cshtml
@@ -0,0 +1,47 @@
+@page
+@model RegisterModel
+@{
+ ViewData["Title"] = "Register";
+}
+
+@ViewData["Title"]
+
+
+
+@section Scripts {
+
+}
diff --git a/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Register.cshtml.cs b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Register.cshtml.cs
new file mode 100644
index 0000000000..35cb402bb8
--- /dev/null
+++ b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/Account/Register.cshtml.cs
@@ -0,0 +1,115 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using IdentitySample.DefaultUI.Data;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Identity.UI.Services;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
+
+namespace IdentitySample.DefaultUI
+{
+ public class RegisterModel : PageModel
+ {
+ private readonly SignInManager _signInManager;
+ private readonly UserManager _userManager;
+ private readonly ILogger _logger;
+ private readonly IEmailSender _emailSender;
+
+ public RegisterModel(
+ UserManager userManager,
+ SignInManager signInManager,
+ ILogger 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]
+ [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; }
+
+ [Required]
+ [DataType(DataType.Text)]
+ [Display(Name = "Full name")]
+ public string Name { get; set; }
+
+ [Required]
+ [Range(0,199, ErrorMessage = "Age must be between 0 and 199 years")]
+ [Display(Name = "Age")]
+ public int Age { get; set; }
+ }
+
+ public void OnGet(string returnUrl = null)
+ {
+ ReturnUrl = returnUrl;
+ }
+
+ public async Task OnPostAsync(string returnUrl = null)
+ {
+ returnUrl = returnUrl ?? Url.Content("~/");
+ if (ModelState.IsValid)
+ {
+ var user = new ApplicationUser {
+ UserName = Input.Email,
+ Email = Input.Email,
+ Name = Input.Name,
+ Age = Input.Age
+ };
+
+ 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 clicking here.");
+
+ 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();
+ }
+ }
+}
diff --git a/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/_ViewImports.cshtml b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/_ViewImports.cshtml
new file mode 100644
index 0000000000..777abd9e19
--- /dev/null
+++ b/samples/IdentitySample.DefaultUI/Areas/Identity/Pages/_ViewImports.cshtml
@@ -0,0 +1,2 @@
+@namespace IdentitySample.DefaultUI
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
diff --git a/samples/IdentitySample.DefaultUI/Data/ApplicationDbContext.cs b/samples/IdentitySample.DefaultUI/Data/ApplicationDbContext.cs
new file mode 100644
index 0000000000..1e96af6bee
--- /dev/null
+++ b/samples/IdentitySample.DefaultUI/Data/ApplicationDbContext.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
+
+namespace IdentitySample.DefaultUI.Data
+{
+ public class ApplicationDbContext : IdentityDbContext
+ {
+ public ApplicationDbContext(DbContextOptions options) : base(options)
+ {
+ }
+ }
+}
diff --git a/samples/IdentitySample.DefaultUI/Data/ApplicationUser.cs b/samples/IdentitySample.DefaultUI/Data/ApplicationUser.cs
new file mode 100644
index 0000000000..134677ce4f
--- /dev/null
+++ b/samples/IdentitySample.DefaultUI/Data/ApplicationUser.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+
+namespace IdentitySample.DefaultUI.Data
+{
+ public class ApplicationUser : IdentityUser
+ {
+ public string Name { get; set; }
+ public int Age { get; set; }
+ }
+}
diff --git a/samples/IdentitySample.DefaultUI/Data/Migrations/20171220235730_CreateIdentitySchema.Designer.cs b/samples/IdentitySample.DefaultUI/Data/Migrations/20180126174859_CreateIdentitySchema.Designer.cs
similarity index 91%
rename from samples/IdentitySample.DefaultUI/Data/Migrations/20171220235730_CreateIdentitySchema.Designer.cs
rename to samples/IdentitySample.DefaultUI/Data/Migrations/20180126174859_CreateIdentitySchema.Designer.cs
index 9d4043e024..acee5cb362 100644
--- a/samples/IdentitySample.DefaultUI/Data/Migrations/20171220235730_CreateIdentitySchema.Designer.cs
+++ b/samples/IdentitySample.DefaultUI/Data/Migrations/20180126174859_CreateIdentitySchema.Designer.cs
@@ -1,26 +1,82 @@
//
using System;
-using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
+using IdentitySample.DefaultUI.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
namespace IdentitySample.DefaultUI.Data.Migrations
{
- [DbContext(typeof(IdentityDbContext))]
- [Migration("20171220235730_CreateIdentitySchema")]
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20180126174859_CreateIdentitySchema")]
partial class CreateIdentitySchema
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "2.1.0-preview1-27965")
+ .HasAnnotation("ProductVersion", "2.1.0-preview1-28153")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+ modelBuilder.Entity("IdentitySample.DefaultUI.Data.ApplicationUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount");
+
+ b.Property("Age");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed");
+
+ b.Property("LockoutEnabled");
+
+ b.Property("LockoutEnd");
+
+ b.Property("Name");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash");
+
+ b.Property("PhoneNumber");
+
+ b.Property("PhoneNumberConfirmed");
+
+ b.Property("SecurityStamp");
+
+ b.Property("TwoFactorEnabled");
+
+ b.Property("UserName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasName("UserNameIndex")
+ .HasFilter("[NormalizedUserName] IS NOT NULL");
+
+ b.ToTable("AspNetUsers");
+ });
+
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property("Id")
@@ -64,57 +120,6 @@ namespace IdentitySample.DefaultUI.Data.Migrations
b.ToTable("AspNetRoleClaims");
});
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd();
-
- b.Property("AccessFailedCount");
-
- b.Property("ConcurrencyStamp")
- .IsConcurrencyToken();
-
- b.Property("Email")
- .HasMaxLength(256);
-
- b.Property("EmailConfirmed");
-
- b.Property("LockoutEnabled");
-
- b.Property("LockoutEnd");
-
- b.Property("NormalizedEmail")
- .HasMaxLength(256);
-
- b.Property("NormalizedUserName")
- .HasMaxLength(256);
-
- b.Property("PasswordHash");
-
- b.Property("PhoneNumber");
-
- b.Property("PhoneNumberConfirmed");
-
- b.Property("SecurityStamp");
-
- b.Property("TwoFactorEnabled");
-
- b.Property("UserName")
- .HasMaxLength(256);
-
- b.HasKey("Id");
-
- b.HasIndex("NormalizedEmail")
- .HasName("EmailIndex");
-
- b.HasIndex("NormalizedUserName")
- .IsUnique()
- .HasName("UserNameIndex")
- .HasFilter("[NormalizedUserName] IS NOT NULL");
-
- b.ToTable("AspNetUsers");
- });
-
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
{
b.Property("Id")
@@ -194,7 +199,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
{
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
+ b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
@@ -202,7 +207,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
{
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
+ b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
@@ -215,7 +220,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
+ b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
@@ -223,7 +228,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
{
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
+ b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
diff --git a/samples/IdentitySample.DefaultUI/Data/Migrations/20171220235730_CreateIdentitySchema.cs b/samples/IdentitySample.DefaultUI/Data/Migrations/20180126174859_CreateIdentitySchema.cs
similarity index 98%
rename from samples/IdentitySample.DefaultUI/Data/Migrations/20171220235730_CreateIdentitySchema.cs
rename to samples/IdentitySample.DefaultUI/Data/Migrations/20180126174859_CreateIdentitySchema.cs
index fcf45f7c3e..713e581f6d 100644
--- a/samples/IdentitySample.DefaultUI/Data/Migrations/20171220235730_CreateIdentitySchema.cs
+++ b/samples/IdentitySample.DefaultUI/Data/Migrations/20180126174859_CreateIdentitySchema.cs
@@ -41,7 +41,9 @@ namespace IdentitySample.DefaultUI.Data.Migrations
TwoFactorEnabled = table.Column(nullable: false),
LockoutEnd = table.Column(nullable: true),
LockoutEnabled = table.Column(nullable: false),
- AccessFailedCount = table.Column(nullable: false)
+ AccessFailedCount = table.Column(nullable: false),
+ Name = table.Column(nullable: true),
+ Age = table.Column(nullable: false)
},
constraints: table =>
{
diff --git a/samples/IdentitySample.DefaultUI/Data/Migrations/IdentityDbContextModelSnapshot.cs b/samples/IdentitySample.DefaultUI/Data/Migrations/ApplicationDbContextModelSnapshot.cs
similarity index 91%
rename from samples/IdentitySample.DefaultUI/Data/Migrations/IdentityDbContextModelSnapshot.cs
rename to samples/IdentitySample.DefaultUI/Data/Migrations/ApplicationDbContextModelSnapshot.cs
index 97f59eff98..8eb1302cd7 100644
--- a/samples/IdentitySample.DefaultUI/Data/Migrations/IdentityDbContextModelSnapshot.cs
+++ b/samples/IdentitySample.DefaultUI/Data/Migrations/ApplicationDbContextModelSnapshot.cs
@@ -1,25 +1,81 @@
//
using System;
-using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
+using IdentitySample.DefaultUI.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
namespace IdentitySample.DefaultUI.Data.Migrations
{
- [DbContext(typeof(IdentityDbContext))]
- partial class IdentityDbContextModelSnapshot : ModelSnapshot
+ [DbContext(typeof(ApplicationDbContext))]
+ partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "2.1.0-preview1-27965")
+ .HasAnnotation("ProductVersion", "2.1.0-preview1-28153")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+ modelBuilder.Entity("IdentitySample.DefaultUI.Data.ApplicationUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount");
+
+ b.Property("Age");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed");
+
+ b.Property("LockoutEnabled");
+
+ b.Property("LockoutEnd");
+
+ b.Property("Name");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash");
+
+ b.Property("PhoneNumber");
+
+ b.Property("PhoneNumberConfirmed");
+
+ b.Property("SecurityStamp");
+
+ b.Property("TwoFactorEnabled");
+
+ b.Property("UserName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasName("UserNameIndex")
+ .HasFilter("[NormalizedUserName] IS NOT NULL");
+
+ b.ToTable("AspNetUsers");
+ });
+
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property("Id")
@@ -63,57 +119,6 @@ namespace IdentitySample.DefaultUI.Data.Migrations
b.ToTable("AspNetRoleClaims");
});
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd();
-
- b.Property("AccessFailedCount");
-
- b.Property("ConcurrencyStamp")
- .IsConcurrencyToken();
-
- b.Property("Email")
- .HasMaxLength(256);
-
- b.Property("EmailConfirmed");
-
- b.Property("LockoutEnabled");
-
- b.Property("LockoutEnd");
-
- b.Property("NormalizedEmail")
- .HasMaxLength(256);
-
- b.Property("NormalizedUserName")
- .HasMaxLength(256);
-
- b.Property("PasswordHash");
-
- b.Property("PhoneNumber");
-
- b.Property("PhoneNumberConfirmed");
-
- b.Property("SecurityStamp");
-
- b.Property("TwoFactorEnabled");
-
- b.Property("UserName")
- .HasMaxLength(256);
-
- b.HasKey("Id");
-
- b.HasIndex("NormalizedEmail")
- .HasName("EmailIndex");
-
- b.HasIndex("NormalizedUserName")
- .IsUnique()
- .HasName("UserNameIndex")
- .HasFilter("[NormalizedUserName] IS NOT NULL");
-
- b.ToTable("AspNetUsers");
- });
-
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
{
b.Property("Id")
@@ -193,7 +198,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
{
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
+ b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
@@ -201,7 +206,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
{
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
+ b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
@@ -214,7 +219,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
+ b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
@@ -222,7 +227,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
{
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
+ b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
diff --git a/samples/IdentitySample.DefaultUI/Startup.cs b/samples/IdentitySample.DefaultUI/Startup.cs
index 65c9629e73..505c7f0490 100644
--- a/samples/IdentitySample.DefaultUI/Startup.cs
+++ b/samples/IdentitySample.DefaultUI/Startup.cs
@@ -1,3 +1,4 @@
+using IdentitySample.DefaultUI.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
@@ -28,12 +29,12 @@ namespace IdentitySample.DefaultUI
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
- services.AddDbContext(
+ services.AddDbContext(
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
x => x.MigrationsAssembly("IdentitySample.DefaultUI")));
- services.AddIdentity(o => o.Stores.MaxLengthForKeys = 128)
- .AddEntityFrameworkStores()
+ services.AddIdentity(o => o.Stores.MaxLengthForKeys = 128)
+ .AddEntityFrameworkStores()
.AddDefaultUI()
.AddDefaultTokenProviders();
diff --git a/samples/IdentitySample.DefaultUI/Views/Shared/_LoginPartial.cshtml b/samples/IdentitySample.DefaultUI/Views/Shared/_LoginPartial.cshtml
index 96228c799e..3e8d8f66d3 100644
--- a/samples/IdentitySample.DefaultUI/Views/Shared/_LoginPartial.cshtml
+++ b/samples/IdentitySample.DefaultUI/Views/Shared/_LoginPartial.cshtml
@@ -1,5 +1,6 @@
-@inject SignInManager SignInManager
-@inject UserManager UserManager
+@using IdentitySample.DefaultUI.Data
+@inject SignInManager SignInManager
+@inject UserManager UserManager
@if (SignInManager.IsSignedIn(User))
{
diff --git a/samples/IdentitySample.DefaultUI/appsettings.json b/samples/IdentitySample.DefaultUI/appsettings.json
index 46fe46e66a..9adcb1012d 100644
--- a/samples/IdentitySample.DefaultUI/appsettings.json
+++ b/samples/IdentitySample.DefaultUI/appsettings.json
@@ -1,6 +1,6 @@
{
"ConnectionStrings": {
- "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-IdentitySample.DefaultUI-2ff9bc27-5e8c-4484-90ca-e3aace89b72a;Trusted_Connection=True;MultipleActiveResultSets=true"
+ "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-IdentitySample.DefaultUI-d97faff4-1cfe-4c5d-b031-aa23aeb03a5e;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
diff --git a/src/UI/Areas/Identity/Filters/ExternalLoginsPageFilter.cs b/src/UI/Areas/Identity/Filters/ExternalLoginsPageFilter.cs
new file mode 100644
index 0000000000..75719adc01
--- /dev/null
+++ b/src/UI/Areas/Identity/Filters/ExternalLoginsPageFilter.cs
@@ -0,0 +1,32 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.AspNetCore.Identity.UI.Areas.Identity.Filters
+{
+ internal class ExternalLoginsPageFilter : IAsyncPageFilter where TUser : class
+ {
+ public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
+ {
+ var result = await next();
+ if (result.Result is PageResult page)
+ {
+ var signInManager = context.HttpContext.RequestServices.GetRequiredService>();
+ var schemes = await signInManager.GetExternalAuthenticationSchemesAsync();
+ var hasExternalLogins = schemes.Any();
+
+ page.ViewData["ManageNav.HasExternalLogins"] = hasExternalLogins;
+ }
+ }
+
+ public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/UI/Areas/Identity/Pages/Account/AccessDenied.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/AccessDenied.cshtml.cs
index 215aacc344..0d0399307d 100644
--- a/src/UI/Areas/Identity/Pages/Account/AccessDenied.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/AccessDenied.cshtml.cs
@@ -3,7 +3,7 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
public class AccessDeniedModel : PageModel
{
diff --git a/src/UI/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs
index e31499f856..8ad4f34427 100644
--- a/src/UI/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs
@@ -6,18 +6,24 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
- public class ConfirmEmailModel : PageModel
+ [IdentityDefaultUI(typeof(ConfirmEmailModel<>))]
+ public abstract class ConfirmEmailModel : PageModel
{
- private readonly UserManager _userManager;
+ public virtual Task OnGetAsync(string userId, string code) => throw new NotImplementedException();
+ }
- public ConfirmEmailModel(UserManager userManager)
+ internal class ConfirmEmailModel : ConfirmEmailModel where TUser : IdentityUser
+ {
+ private readonly UserManager _userManager;
+
+ public ConfirmEmailModel(UserManager userManager)
{
_userManager = userManager;
}
- public async Task OnGetAsync(string userId, string code)
+ public override async Task OnGetAsync(string userId, string code)
{
if (userId == null || code == null)
{
diff --git a/src/UI/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs
index 85b015a642..8a04c751b7 100644
--- a/src/UI/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.ComponentModel.DataAnnotations;
using System.Security.Claims;
using System.Threading.Tasks;
@@ -8,24 +9,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
+ [IdentityDefaultUI(typeof(ExternalLoginModel<>))]
public class ExternalLoginModel : PageModel
{
- private readonly SignInManager _signInManager;
- private readonly UserManager _userManager;
- private readonly ILogger _logger;
-
- public ExternalLoginModel(
- SignInManager signInManager,
- UserManager userManager,
- ILogger logger)
- {
- _signInManager = signInManager;
- _userManager = userManager;
- _logger = logger;
- }
-
[BindProperty]
public InputModel Input { get; set; }
@@ -43,12 +31,37 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
public string Email { get; set; }
}
- public IActionResult OnGetAsync()
+ public virtual IActionResult OnGet() => throw new NotImplementedException();
+
+ public virtual IActionResult OnPost(string provider, string returnUrl = null) => throw new NotImplementedException();
+
+ public virtual Task OnGetCallbackAsync(string returnUrl = null, string remoteError = null) => throw new NotImplementedException();
+
+ public virtual Task OnPostConfirmationAsync(string returnUrl = null) => throw new NotImplementedException();
+ }
+
+ internal class ExternalLoginModel : ExternalLoginModel where TUser : IdentityUser, new()
+ {
+ private readonly SignInManager _signInManager;
+ private readonly UserManager _userManager;
+ private readonly ILogger _logger;
+
+ public ExternalLoginModel(
+ SignInManager signInManager,
+ UserManager userManager,
+ ILogger logger)
+ {
+ _signInManager = signInManager;
+ _userManager = userManager;
+ _logger = logger;
+ }
+
+ public override IActionResult OnGet()
{
return RedirectToPage("./Login");
}
- public IActionResult OnPost(string provider, string returnUrl = null)
+ public override IActionResult OnPost(string provider, string returnUrl = null)
{
// Request a redirect to the external login provider.
var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
@@ -56,7 +69,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
return new ChallengeResult(provider, properties);
}
- public async Task OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
+ public override async Task OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (remoteError != null)
@@ -98,20 +111,20 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
}
}
- public async Task OnPostConfirmationAsync(string returnUrl = null)
+ public override async Task OnPostConfirmationAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
// Get the information about the user from the external login provider
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
- ErrorMessage = "Error loading external login information during confirmation.";
- return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
+ ErrorMessage = "Error loading external login information during confirmation.";
+ return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
if (ModelState.IsValid)
{
- var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
+ var user = new TUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user);
if (result.Succeeded)
{
diff --git a/src/UI/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs
index d41f2e9769..ef7dd95b92 100644
--- a/src/UI/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.ComponentModel.DataAnnotations;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
@@ -8,19 +9,11 @@ using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
- public class ForgotPasswordModel : PageModel
+ [IdentityDefaultUI(typeof(ForgotPasswordModel<>))]
+ public abstract class ForgotPasswordModel : PageModel
{
- private readonly UserManager _userManager;
- private readonly IEmailSender _emailSender;
-
- public ForgotPasswordModel(UserManager userManager, IEmailSender emailSender)
- {
- _userManager = userManager;
- _emailSender = emailSender;
- }
-
[BindProperty]
public InputModel Input { get; set; }
@@ -31,7 +24,21 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
public string Email { get; set; }
}
- public async Task OnPostAsync()
+ public virtual Task OnPostAsync() => throw new NotImplementedException();
+ }
+
+ internal class ForgotPasswordModel : ForgotPasswordModel where TUser : IdentityUser
+ {
+ private readonly UserManager _userManager;
+ private readonly IEmailSender _emailSender;
+
+ public ForgotPasswordModel(UserManager userManager, IEmailSender emailSender)
+ {
+ _userManager = userManager;
+ _emailSender = emailSender;
+ }
+
+ public override async Task OnPostAsync()
{
if (ModelState.IsValid)
{
diff --git a/src/UI/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs
index 4004302446..77bdaa352c 100644
--- a/src/UI/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs
@@ -3,7 +3,7 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
public class ForgotPasswordConfirmation : PageModel
{
diff --git a/src/UI/Areas/Identity/Pages/Account/Lockout.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/Lockout.cshtml.cs
index e9cd1274ad..33a13a0ced 100644
--- a/src/UI/Areas/Identity/Pages/Account/Lockout.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/Lockout.cshtml.cs
@@ -3,7 +3,7 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
public class LockoutModel : PageModel
{
diff --git a/src/UI/Areas/Identity/Pages/Account/Login.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/Login.cshtml.cs
index 3df8a0e1e6..d8a55a740a 100644
--- a/src/UI/Areas/Identity/Pages/Account/Login.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/Login.cshtml.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@@ -10,19 +11,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
- public class LoginModel : PageModel
+ [IdentityDefaultUI(typeof(LoginModel<>))]
+ public abstract class LoginModel : PageModel
{
- private readonly SignInManager _signInManager;
- private readonly ILogger _logger;
-
- public LoginModel(SignInManager signInManager, ILogger logger)
- {
- _signInManager = signInManager;
- _logger = logger;
- }
-
[BindProperty]
public InputModel Input { get; set; }
@@ -47,7 +40,23 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
public bool RememberMe { get; set; }
}
- public async Task OnGetAsync(string returnUrl = null)
+ public virtual Task OnGetAsync(string returnUrl = null) => throw new NotImplementedException();
+
+ public virtual Task OnPostAsync(string returnUrl = null) => throw new NotImplementedException();
+ }
+
+ internal class LoginModel : LoginModel where TUser : IdentityUser
+ {
+ private readonly SignInManager _signInManager;
+ private readonly ILogger _logger;
+
+ public LoginModel(SignInManager signInManager, ILogger logger)
+ {
+ _signInManager = signInManager;
+ _logger = logger;
+ }
+
+ public override async Task OnGetAsync(string returnUrl = null)
{
if (!string.IsNullOrEmpty(ErrorMessage))
{
@@ -64,7 +73,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
ReturnUrl = returnUrl;
}
- public async Task OnPostAsync(string returnUrl = null)
+ public override async Task OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
diff --git a/src/UI/Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs
index fa2a15e5c8..cd605793fd 100644
--- a/src/UI/Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs
@@ -8,19 +8,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
- public class LoginWith2faModel : PageModel
+ [IdentityDefaultUI(typeof(LoginWith2faModel<>))]
+ public abstract class LoginWith2faModel : PageModel
{
- private readonly SignInManager _signInManager;
- private readonly ILogger _logger;
-
- public LoginWith2faModel(SignInManager signInManager, ILogger logger)
- {
- _signInManager = signInManager;
- _logger = logger;
- }
-
[BindProperty]
public InputModel Input { get; set; }
@@ -40,7 +32,23 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
public bool RememberMachine { get; set; }
}
- public async Task OnGetAsync(bool rememberMe, string returnUrl = null)
+ public virtual Task OnGetAsync(bool rememberMe, string returnUrl = null) => throw new NotImplementedException();
+
+ public virtual Task OnPostAsync(bool rememberMe, string returnUrl = null) => throw new NotImplementedException();
+ }
+
+ internal class LoginWith2faModel : LoginWith2faModel where TUser : IdentityUser
+ {
+ private readonly SignInManager _signInManager;
+ private readonly ILogger _logger;
+
+ public LoginWith2faModel(SignInManager signInManager, ILogger logger)
+ {
+ _signInManager = signInManager;
+ _logger = logger;
+ }
+
+ public override async Task OnGetAsync(bool rememberMe, string returnUrl = null)
{
// Ensure the user has gone through the username & password screen first
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
@@ -56,7 +64,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
return Page();
}
- public async Task OnPostAsync(bool rememberMe, string returnUrl = null)
+ public override async Task OnPostAsync(bool rememberMe, string returnUrl = null)
{
if (!ModelState.IsValid)
{
@@ -91,6 +99,6 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
ModelState.AddModelError(string.Empty, "Invalid authenticator code.");
return Page();
}
- }
+ }
}
}
diff --git a/src/UI/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml.cs
index 449ab13526..128771ae78 100644
--- a/src/UI/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml.cs
@@ -8,19 +8,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
- public class LoginWithRecoveryCodeModel : PageModel
+ [IdentityDefaultUI(typeof(LoginWithRecoveryCodeModel<>))]
+ public abstract class LoginWithRecoveryCodeModel : PageModel
{
- private readonly SignInManager _signInManager;
- private readonly ILogger _logger;
-
- public LoginWithRecoveryCodeModel(SignInManager signInManager, ILogger logger)
- {
- _signInManager = signInManager;
- _logger = logger;
- }
-
[BindProperty]
public InputModel Input { get; set; }
@@ -35,7 +27,23 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
public string RecoveryCode { get; set; }
}
- public async Task OnGetAsync(string returnUrl = null)
+ public virtual Task OnGetAsync(string returnUrl = null) => throw new NotImplementedException();
+
+ public virtual Task OnPostAsync(string returnUrl = null) => throw new NotImplementedException();
+ }
+
+ internal class LoginWithRecoveryCodeModel : LoginWithRecoveryCodeModel where TUser : IdentityUser
+ {
+ private readonly SignInManager _signInManager;
+ private readonly ILogger _logger;
+
+ public LoginWithRecoveryCodeModel(SignInManager signInManager, ILogger logger)
+ {
+ _signInManager = signInManager;
+ _logger = logger;
+ }
+
+ public override async Task OnGetAsync(string returnUrl = null)
{
// Ensure the user has gone through the username & password screen first
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
@@ -49,7 +57,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
return Page();
}
- public async Task OnPostAsync(string returnUrl = null)
+ public override async Task OnPostAsync(string returnUrl = null)
{
if (!ModelState.IsValid)
{
@@ -65,7 +73,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty);
var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode);
-
+
if (result.Succeeded)
{
_logger.LogInformation("User with ID '{UserId}' logged in with a recovery code.", user.Id);
diff --git a/src/UI/Areas/Identity/Pages/Account/Logout.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/Logout.cshtml.cs
index 672bc9b8b2..1ca9dbee37 100644
--- a/src/UI/Areas/Identity/Pages/Account/Logout.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/Logout.cshtml.cs
@@ -1,29 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{
- public class LogoutModel : PageModel
+ [IdentityDefaultUI(typeof(LogoutModel<>))]
+ public abstract class LogoutModel : PageModel
{
- private readonly SignInManager _signInManager;
+ public void OnGet()
+ {
+ }
+
+ public virtual Task OnPost(string returnUrl = null) => throw new NotImplementedException();
+ }
+
+ internal class LogoutModel : LogoutModel where TUser : IdentityUser
+ {
+ private readonly SignInManager _signInManager;
private readonly ILogger _logger;
- public LogoutModel(SignInManager signInManager, ILogger logger)
+ public LogoutModel(SignInManager signInManager, ILogger logger)
{
_signInManager = signInManager;
_logger = logger;
}
- public void OnGet()
- {
- }
-
- public async Task OnPost(string returnUrl = null)
+ public override async Task OnPost(string returnUrl = null)
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
diff --git a/src/UI/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml.cs
index 025cbad728..c44118ae9c 100644
--- a/src/UI/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml.cs
@@ -8,24 +8,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
- public class ChangePasswordModel : PageModel
+ [IdentityDefaultUI(typeof(ChangePasswordModel<>))]
+ public abstract class ChangePasswordModel : PageModel
{
- private readonly UserManager _userManager;
- private readonly SignInManager _signInManager;
- private readonly ILogger _logger;
-
- public ChangePasswordModel(
- UserManager userManager,
- SignInManager signInManager,
- ILogger logger)
- {
- _userManager = userManager;
- _signInManager = signInManager;
- _logger = logger;
- }
-
[BindProperty]
public InputModel Input { get; set; }
@@ -51,7 +38,28 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
public string ConfirmPassword { get; set; }
}
- public async Task OnGetAsync()
+ public virtual Task OnGetAsync() => throw new NotImplementedException();
+
+ public virtual Task OnPostAsync() => throw new NotImplementedException();
+ }
+
+ internal class ChangePasswordModel : ChangePasswordModel where TUser : IdentityUser
+ {
+ private readonly UserManager _userManager;
+ private readonly SignInManager _signInManager;
+ private readonly ILogger _logger;
+
+ public ChangePasswordModel(
+ UserManager userManager,
+ SignInManager signInManager,
+ ILogger logger)
+ {
+ _userManager = userManager;
+ _signInManager = signInManager;
+ _logger = logger;
+ }
+
+ public override async Task OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@@ -68,7 +76,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
- public async Task OnPostAsync()
+ public override async Task OnPostAsync()
{
if (!ModelState.IsValid)
{
diff --git a/src/UI/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml.cs
index 12b227de58..7d7b074d2b 100644
--- a/src/UI/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml.cs
@@ -8,24 +8,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
- public class DeletePersonalDataModel : PageModel
+ [IdentityDefaultUI(typeof(DeletePersonalDataModel<>))]
+ public abstract class DeletePersonalDataModel : PageModel
{
- private readonly UserManager _userManager;
- private readonly SignInManager _signInManager;
- private readonly ILogger _logger;
-
- public DeletePersonalDataModel(
- UserManager userManager,
- SignInManager signInManager,
- ILogger logger)
- {
- _userManager = userManager;
- _signInManager = signInManager;
- _logger = logger;
- }
-
[BindProperty]
public InputModel Input { get; set; }
@@ -38,7 +25,28 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
public bool RequirePassword { get; set; }
- public async Task OnGet()
+ public virtual Task OnGet() => throw new NotImplementedException();
+
+ public virtual Task OnPostAsync() => throw new NotImplementedException();
+ }
+
+ internal class DeletePersonalDataModel : DeletePersonalDataModel where TUser : IdentityUser
+ {
+ private readonly UserManager _userManager;
+ private readonly SignInManager _signInManager;
+ private readonly ILogger _logger;
+
+ public DeletePersonalDataModel(
+ UserManager userManager,
+ SignInManager signInManager,
+ ILogger logger)
+ {
+ _userManager = userManager;
+ _signInManager = signInManager;
+ _logger = logger;
+ }
+
+ public override async Task OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@@ -50,7 +58,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
- public async Task OnPostAsync()
+ public override async Task OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
diff --git a/src/UI/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs
index 6bcc873df5..d0c0f70d4b 100644
--- a/src/UI/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs
@@ -7,25 +7,33 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
- public class Disable2faModel : PageModel
+ [IdentityDefaultUI(typeof(Disable2faModel<>))]
+ public abstract class Disable2faModel : PageModel
{
- private readonly UserManager _userManager;
+ [TempData]
+ public string StatusMessage { get; set; }
+
+ public virtual Task OnGet() => throw new NotImplementedException();
+
+ public virtual Task OnPostAsync() => throw new NotImplementedException();
+ }
+
+ internal class Disable2faModel : Disable2faModel where TUser : IdentityUser
+ {
+ private readonly UserManager _userManager;
private readonly ILogger _logger;
public Disable2faModel(
- UserManager userManager,
+ UserManager userManager,
ILogger logger)
{
_userManager = userManager;
_logger = logger;
}
- [TempData]
- public string StatusMessage { get; set; }
-
- public async Task OnGet()
+ public override async Task OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@@ -41,7 +49,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
- public async Task OnPostAsync()
+ public override async Task OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
diff --git a/src/UI/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs b/src/UI/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs
index 4420e89748..0096b0f4d9 100644
--- a/src/UI/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs
+++ b/src/UI/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs
@@ -9,22 +9,28 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
-namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
+namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
- public class DownloadPersonalDataModel : PageModel
+ [IdentityDefaultUI(typeof(DownloadPersonalDataModel<>))]
+ public abstract class DownloadPersonalDataModel : PageModel
{
- private readonly UserManager _userManager;
+ public virtual Task OnPostAsync() => throw new NotImplementedException();
+ }
+
+ internal class DownloadPersonalDataModel : DownloadPersonalDataModel where TUser : IdentityUser
+ {
+ private readonly UserManager