Merge branch 'release/2.1' into origin-dev

This commit is contained in:
Javier Calvarro Nelson 2018-01-26 16:15:20 -08:00
commit d05ddf9564
49 changed files with 1128 additions and 431 deletions

View File

@ -0,0 +1,53 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Profile";
}
<h4>@ViewData["Title"]</h4>
@Html.Partial("_StatusMessage", Model.StatusMessage)
<div class="row">
<div class="col-md-6">
<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.Age"></label>
<input asp-for="Input.Age" class="form-control" />
</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 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.PhoneNumber"></label>
<input asp-for="Input.PhoneNumber" class="form-control" />
<span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-default">Save</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -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<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
public IndexModel(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> 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<IActionResult> 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<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)}'.");
}
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<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 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 <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
StatusMessage = "Verification email sent. Please check your email.";
return RedirectToPage();
}
}
}

View File

@ -0,0 +1,47 @@
@page
@model RegisterModel
@{
ViewData["Title"] = "Register";
}
<h2>@ViewData["Title"]</h2>
<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.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>
<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.Age"></label>
<input asp-for="Input.Age" class="form-control" />
<span asp-validation-for="Input.Age" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-default">Register</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -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<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender;
public RegisterModel(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> 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]
[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<IActionResult> 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 <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();
}
}
}

View File

@ -0,0 +1,2 @@
@namespace IdentitySample.DefaultUI
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -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<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
}
}

View File

@ -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; }
}
}

View File

@ -1,26 +1,82 @@
// <auto-generated />
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<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<int>("Age");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("Name");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("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<string>("Id")
@ -64,57 +120,6 @@ namespace IdentitySample.DefaultUI.Data.Migrations
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("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<string>", b =>
{
b.Property<int>("Id")
@ -194,7 +199,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", 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<string>", 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<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);

View File

@ -41,7 +41,9 @@ namespace IdentitySample.DefaultUI.Data.Migrations
TwoFactorEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
LockoutEnabled = table.Column<bool>(nullable: false),
AccessFailedCount = table.Column<int>(nullable: false)
AccessFailedCount = table.Column<int>(nullable: false),
Name = table.Column<string>(nullable: true),
Age = table.Column<int>(nullable: false)
},
constraints: table =>
{

View File

@ -1,25 +1,81 @@
// <auto-generated />
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<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<int>("Age");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("Name");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("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<string>("Id")
@ -63,57 +119,6 @@ namespace IdentitySample.DefaultUI.Data.Migrations
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("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<string>", b =>
{
b.Property<int>("Id")
@ -193,7 +198,7 @@ namespace IdentitySample.DefaultUI.Data.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", 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<string>", 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<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
b.HasOne("IdentitySample.DefaultUI.Data.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);

View File

@ -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<IdentityDbContext>(
services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
x => x.MigrationsAssembly("IdentitySample.DefaultUI")));
services.AddIdentity<IdentityUser, IdentityRole>(o => o.Stores.MaxLengthForKeys = 128)
.AddEntityFrameworkStores<IdentityDbContext>()
services.AddIdentity<ApplicationUser, IdentityRole>(o => o.Stores.MaxLengthForKeys = 128)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultUI()
.AddDefaultTokenProviders();

View File

@ -1,5 +1,6 @@
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@using IdentitySample.DefaultUI.Data
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@if (SignInManager.IsSignedIn(User))
{

View File

@ -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,

View File

@ -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<TUser> : 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<SignInManager<TUser>>();
var schemes = await signInManager.GetExternalAuthenticationSchemesAsync();
var hasExternalLogins = schemes.Any();
page.ViewData["ManageNav.HasExternalLogins"] = hasExternalLogins;
}
}
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
return Task.CompletedTask;
}
}
}

View File

@ -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
{

View File

@ -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<IdentityUser> _userManager;
public virtual Task<IActionResult> OnGetAsync(string userId, string code) => throw new NotImplementedException();
}
public ConfirmEmailModel(UserManager<IdentityUser> userManager)
internal class ConfirmEmailModel<TUser> : ConfirmEmailModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
public ConfirmEmailModel(UserManager<TUser> userManager)
{
_userManager = userManager;
}
public async Task<IActionResult> OnGetAsync(string userId, string code)
public override async Task<IActionResult> OnGetAsync(string userId, string code)
{
if (userId == null || code == null)
{

View File

@ -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<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
private readonly ILogger<ExternalLoginModel> _logger;
public ExternalLoginModel(
SignInManager<IdentityUser> signInManager,
UserManager<IdentityUser> userManager,
ILogger<ExternalLoginModel> 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<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null) => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null) => throw new NotImplementedException();
}
internal class ExternalLoginModel<TUser> : ExternalLoginModel where TUser : IdentityUser, new()
{
private readonly SignInManager<TUser> _signInManager;
private readonly UserManager<TUser> _userManager;
private readonly ILogger<ExternalLoginModel> _logger;
public ExternalLoginModel(
SignInManager<TUser> signInManager,
UserManager<TUser> userManager,
ILogger<ExternalLoginModel> 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<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
public override async Task<IActionResult> 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<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
public override async Task<IActionResult> 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)
{

View File

@ -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<IdentityUser> _userManager;
private readonly IEmailSender _emailSender;
public ForgotPasswordModel(UserManager<IdentityUser> 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<IActionResult> OnPostAsync()
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class ForgotPasswordModel<TUser> : ForgotPasswordModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly IEmailSender _emailSender;
public ForgotPasswordModel(UserManager<TUser> userManager, IEmailSender emailSender)
{
_userManager = userManager;
_emailSender = emailSender;
}
public override async Task<IActionResult> OnPostAsync()
{
if (ModelState.IsValid)
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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<IdentityUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
public LoginModel(SignInManager<IdentityUser> signInManager, ILogger<LoginModel> 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<IActionResult> OnPostAsync(string returnUrl = null) => throw new NotImplementedException();
}
internal class LoginModel<TUser> : LoginModel where TUser : IdentityUser
{
private readonly SignInManager<TUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
public LoginModel(SignInManager<TUser> signInManager, ILogger<LoginModel> 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<IActionResult> OnPostAsync(string returnUrl = null)
public override async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");

View File

@ -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<IdentityUser> _signInManager;
private readonly ILogger<LoginWith2faModel> _logger;
public LoginWith2faModel(SignInManager<IdentityUser> signInManager, ILogger<LoginWith2faModel> 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<IActionResult> OnGetAsync(bool rememberMe, string returnUrl = null)
public virtual Task<IActionResult> OnGetAsync(bool rememberMe, string returnUrl = null) => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync(bool rememberMe, string returnUrl = null) => throw new NotImplementedException();
}
internal class LoginWith2faModel<TUser> : LoginWith2faModel where TUser : IdentityUser
{
private readonly SignInManager<TUser> _signInManager;
private readonly ILogger<LoginWith2faModel> _logger;
public LoginWith2faModel(SignInManager<TUser> signInManager, ILogger<LoginWith2faModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
public override async Task<IActionResult> 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<IActionResult> OnPostAsync(bool rememberMe, string returnUrl = null)
public override async Task<IActionResult> 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();
}
}
}
}
}

View File

@ -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<IdentityUser> _signInManager;
private readonly ILogger<LoginWithRecoveryCodeModel> _logger;
public LoginWithRecoveryCodeModel(SignInManager<IdentityUser> signInManager, ILogger<LoginWithRecoveryCodeModel> 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<IActionResult> OnGetAsync(string returnUrl = null)
public virtual Task<IActionResult> OnGetAsync(string returnUrl = null) => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync(string returnUrl = null) => throw new NotImplementedException();
}
internal class LoginWithRecoveryCodeModel<TUser> : LoginWithRecoveryCodeModel where TUser : IdentityUser
{
private readonly SignInManager<TUser> _signInManager;
private readonly ILogger<LoginWithRecoveryCodeModel> _logger;
public LoginWithRecoveryCodeModel(SignInManager<TUser> signInManager, ILogger<LoginWithRecoveryCodeModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
public override async Task<IActionResult> 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<IActionResult> OnPostAsync(string returnUrl = null)
public override async Task<IActionResult> 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);

View File

@ -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<IdentityUser> _signInManager;
public void OnGet()
{
}
public virtual Task<IActionResult> OnPost(string returnUrl = null) => throw new NotImplementedException();
}
internal class LogoutModel<TUser> : LogoutModel where TUser : IdentityUser
{
private readonly SignInManager<TUser> _signInManager;
private readonly ILogger<LogoutModel> _logger;
public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
public LogoutModel(SignInManager<TUser> signInManager, ILogger<LogoutModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
public void OnGet()
{
}
public async Task<IActionResult> OnPost(string returnUrl = null)
public override async Task<IActionResult> OnPost(string returnUrl = null)
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");

View File

@ -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<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<ChangePasswordModel> _logger;
public ChangePasswordModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<ChangePasswordModel> 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<IActionResult> OnGetAsync()
public virtual Task<IActionResult> OnGetAsync() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class ChangePasswordModel<TUser> : ChangePasswordModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly SignInManager<TUser> _signInManager;
private readonly ILogger<ChangePasswordModel> _logger;
public ChangePasswordModel(
UserManager<TUser> userManager,
SignInManager<TUser> signInManager,
ILogger<ChangePasswordModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
public override async Task<IActionResult> 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<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{

View File

@ -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<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<DeletePersonalDataModel> _logger;
public DeletePersonalDataModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<DeletePersonalDataModel> 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<IActionResult> OnGet()
public virtual Task<IActionResult> OnGet() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class DeletePersonalDataModel<TUser> : DeletePersonalDataModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly SignInManager<TUser> _signInManager;
private readonly ILogger<DeletePersonalDataModel> _logger;
public DeletePersonalDataModel(
UserManager<TUser> userManager,
SignInManager<TUser> signInManager,
ILogger<DeletePersonalDataModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
public override async Task<IActionResult> 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<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)

View File

@ -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<IdentityUser> _userManager;
[TempData]
public string StatusMessage { get; set; }
public virtual Task<IActionResult> OnGet() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class Disable2faModel<TUser> : Disable2faModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly ILogger<Disable2faModel> _logger;
public Disable2faModel(
UserManager<IdentityUser> userManager,
UserManager<TUser> userManager,
ILogger<Disable2faModel> logger)
{
_userManager = userManager;
_logger = logger;
}
[TempData]
public string StatusMessage { get; set; }
public async Task<IActionResult> OnGet()
public override async Task<IActionResult> 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<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)

View File

@ -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<IdentityUser> _userManager;
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class DownloadPersonalDataModel<TUser> : DownloadPersonalDataModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly ILogger<DownloadPersonalDataModel> _logger;
public DownloadPersonalDataModel(
UserManager<IdentityUser> userManager,
UserManager<TUser> userManager,
ILogger<DownloadPersonalDataModel> logger)
{
_userManager = userManager;
_logger = logger;
}
public async Task<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)

View File

@ -10,26 +10,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
{
[IdentityDefaultUI(typeof(EnableAuthenticatorModel<>))]
public class EnableAuthenticatorModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly ILogger<EnableAuthenticatorModel> _logger;
private readonly UrlEncoder _urlEncoder;
private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
public EnableAuthenticatorModel(
UserManager<IdentityUser> userManager,
ILogger<EnableAuthenticatorModel> logger,
UrlEncoder urlEncoder)
{
_userManager = userManager;
_logger = logger;
_urlEncoder = urlEncoder;
}
public string SharedKey { get; set; }
public string AuthenticatorUri { get; set; }
@ -52,7 +37,30 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
public string Code { get; set; }
}
public async Task<IActionResult> OnGetAsync()
public virtual Task<IActionResult> OnGetAsync() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class EnableAuthenticatorModel<TUser> : EnableAuthenticatorModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly ILogger<EnableAuthenticatorModel> _logger;
private readonly UrlEncoder _urlEncoder;
private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
public EnableAuthenticatorModel(
UserManager<TUser> userManager,
ILogger<EnableAuthenticatorModel> logger,
UrlEncoder urlEncoder)
{
_userManager = userManager;
_logger = logger;
_urlEncoder = urlEncoder;
}
public override async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@ -65,7 +73,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
public async Task<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@ -109,7 +117,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
}
}
private async Task LoadSharedKeyAndQrCodeUriAsync(IdentityUser user)
private async Task LoadSharedKeyAndQrCodeUriAsync(TUser user)
{
// Load the authenticator key & QR code URI to display on the form
var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);

View File

@ -9,21 +9,11 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
public class ExternalLoginsModel : PageModel
[IdentityDefaultUI(typeof(ExternalLoginsModel<>))]
public abstract class ExternalLoginsModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
public ExternalLoginsModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public IList<UserLoginInfo> CurrentLogins { get; set; }
public IList<AuthenticationScheme> OtherLogins { get; set; }
@ -33,7 +23,29 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
[TempData]
public string StatusMessage { get; set; }
public async Task<IActionResult> OnGetAsync()
public virtual Task<IActionResult> OnGetAsync() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostRemoveLoginAsync(string loginProvider, string providerKey) => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostLinkLoginAsync(string provider) => throw new NotImplementedException();
public virtual Task<IActionResult> OnGetLinkLoginCallbackAsync() => throw new NotImplementedException();
}
internal class ExternalLoginsModel<TUser> : ExternalLoginsModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly SignInManager<TUser> _signInManager;
public ExternalLoginsModel(
UserManager<TUser> userManager,
SignInManager<TUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public override async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@ -49,7 +61,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
public async Task<IActionResult> OnPostRemoveLoginAsync(string loginProvider, string providerKey)
public override async Task<IActionResult> OnPostRemoveLoginAsync(string loginProvider, string providerKey)
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@ -68,7 +80,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return RedirectToPage();
}
public async Task<IActionResult> OnPostLinkLoginAsync(string provider)
public override async Task<IActionResult> OnPostLinkLoginAsync(string provider)
{
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
@ -79,7 +91,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return new ChallengeResult(provider, properties);
}
public async Task<IActionResult> OnGetLinkLoginCallbackAsync()
public override async Task<IActionResult> OnGetLinkLoginCallbackAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)

View File

@ -8,28 +8,36 @@ 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 GenerateRecoveryCodesModel : PageModel
[IdentityDefaultUI(typeof(GenerateRecoveryCodesModel<>))]
public abstract class GenerateRecoveryCodesModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly ILogger<GenerateRecoveryCodesModel> _logger;
public GenerateRecoveryCodesModel(
UserManager<IdentityUser> userManager,
ILogger<GenerateRecoveryCodesModel> logger)
{
_userManager = userManager;
_logger = logger;
}
[TempData]
public string[] RecoveryCodes { get; set; }
[TempData]
public string StatusMessage { get; set; }
public async Task<IActionResult> OnGetAsync()
public virtual Task<IActionResult> OnGetAsync() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class GenerateRecoveryCodesModel<TUser> : GenerateRecoveryCodesModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly ILogger<GenerateRecoveryCodesModel> _logger;
public GenerateRecoveryCodesModel(
UserManager<TUser> userManager,
ILogger<GenerateRecoveryCodesModel> logger)
{
_userManager = userManager;
_logger = logger;
}
public override async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@ -45,7 +53,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
public async Task<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)

View File

@ -9,24 +9,11 @@ using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
public partial class IndexModel : PageModel
[IdentityDefaultUI(typeof(IndexModel<>))]
public abstract class IndexModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly IEmailSender _emailSender;
public IndexModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
}
public string Username { get; set; }
public bool IsEmailConfirmed { get; set; }
@ -48,7 +35,30 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
public string PhoneNumber { get; set; }
}
public async Task<IActionResult> OnGetAsync()
public virtual Task<IActionResult> OnGetAsync() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostSendVerificationEmailAsync() => throw new NotImplementedException();
}
internal class IndexModel<TUser> : IndexModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly SignInManager<TUser> _signInManager;
private readonly IEmailSender _emailSender;
public IndexModel(
UserManager<TUser> userManager,
SignInManager<TUser> signInManager,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
}
public override async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@ -69,7 +79,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
public async Task<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
@ -103,7 +113,8 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
StatusMessage = "Your profile has been updated";
return RedirectToPage();
}
public async Task<IActionResult> OnPostSendVerificationEmailAsync()
public override async Task<IActionResult> OnPostSendVerificationEmailAsync()
{
if (!ModelState.IsValid)
{

View File

@ -4,7 +4,7 @@
using System;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
public static class ManageNavPages
{

View File

@ -1,27 +1,34 @@
// 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.Manage
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
public class PersonalDataModel : PageModel
[IdentityDefaultUI(typeof(PersonalDataModel<>))]
public abstract class PersonalDataModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
public virtual Task<IActionResult> OnGet() => throw new NotImplementedException();
}
internal class PersonalDataModel<TUser> : PersonalDataModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly ILogger<PersonalDataModel> _logger;
public PersonalDataModel(
UserManager<IdentityUser> userManager,
UserManager<TUser> userManager,
ILogger<PersonalDataModel> logger)
{
_userManager = userManager;
_logger = logger;
}
public async Task<IActionResult> OnGet()
public override async Task<IActionResult> OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)

View File

@ -6,25 +6,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 ResetAuthenticatorModel : PageModel
[IdentityDefaultUI(typeof(ResetAuthenticatorModel<>))]
public abstract class ResetAuthenticatorModel : PageModel
{
UserManager<IdentityUser> _userManager;
[TempData]
public string StatusMessage { get; set; }
public virtual Task<IActionResult> OnGet() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class ResetAuthenticatorModel<TUser> : ResetAuthenticatorModel where TUser : IdentityUser
{
UserManager<TUser> _userManager;
ILogger<ResetAuthenticatorModel> _logger;
public ResetAuthenticatorModel(
UserManager<IdentityUser> userManager,
UserManager<TUser> userManager,
ILogger<ResetAuthenticatorModel> logger)
{
_userManager = userManager;
_logger = logger;
}
[TempData]
public string StatusMessage { get; set; }
public async Task<IActionResult> OnGet()
public override async Task<IActionResult> OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@ -35,7 +43,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
public async Task<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)

View File

@ -7,21 +7,11 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
public class SetPasswordModel : PageModel
[IdentityDefaultUI(typeof(SetPasswordModel<>))]
public abstract class SetPasswordModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
public SetPasswordModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
[BindProperty]
public InputModel Input { get; set; }
@ -42,7 +32,25 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
public string ConfirmPassword { get; set; }
}
public async Task<IActionResult> OnGetAsync()
public virtual Task<IActionResult> OnGetAsync() => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
internal class SetPasswordModel<TUser> : SetPasswordModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly SignInManager<TUser> _signInManager;
public SetPasswordModel(
UserManager<TUser> userManager,
SignInManager<TUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public override async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
@ -60,7 +68,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
return Page();
}
public async Task<IActionResult> OnPostAsync()
public override async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{

View File

@ -4,7 +4,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
{
public class ShowRecoveryCodesModel : PageModel
{

View File

@ -6,28 +6,16 @@ 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 TwoFactorAuthenticationModel : PageModel
[IdentityDefaultUI(typeof(TwoFactorAuthenticationModel<>))]
public abstract class TwoFactorAuthenticationModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<TwoFactorAuthenticationModel> _logger;
public TwoFactorAuthenticationModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<TwoFactorAuthenticationModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
public bool HasAuthenticator { get; set; }
public int RecoveryCodesLeft { get; set; }
[BindProperty]
public bool Is2faEnabled { get; set; }
public bool IsMachineRemembered { get; set; }
@ -35,7 +23,24 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
[TempData]
public string StatusMessage { get; set; }
public async Task<IActionResult> OnGet()
public virtual Task<IActionResult> OnGet() => throw new NotImplementedException();
}
internal class TwoFactorAuthenticationModel<TUser> : TwoFactorAuthenticationModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
private readonly SignInManager<TUser> _signInManager;
private readonly ILogger<TwoFactorAuthenticationModel> _logger;
public TwoFactorAuthenticationModel(
UserManager<TUser> userManager, SignInManager<TUser> signInManager, ILogger<TwoFactorAuthenticationModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
public override async Task<IActionResult> OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)

View File

@ -1,12 +1,7 @@
@inject SignInManager<IdentityUser> SignInManager
@{
var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<ul class="nav nav-pills nav-stacked">
<ul class="nav nav-pills nav-stacked">
<li class="@ManageNavPages.IndexNavClass(ViewContext)"><a asp-page="./Index">Profile</a></li>
<li class="@ManageNavPages.ChangePasswordNavClass(ViewContext)"><a asp-page="./ChangePassword">Password</a></li>
@if (hasExternalLogins)
@if ((bool)ViewData["ManageNav.HasExternalLogins"])
{
<li class="@ManageNavPages.ExternalLoginsNavClass(ViewContext)"><a asp-page="./ExternalLogins">External logins</a></li>
}

View File

@ -1 +1 @@
@using Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage
@using Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal

View File

@ -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;
@ -9,27 +10,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 RegisterModel : PageModel
[IdentityDefaultUI(typeof(RegisterModel<>))]
public abstract class RegisterModel : PageModel
{
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
private readonly ILogger<LoginModel> _logger;
private readonly IEmailSender _emailSender;
public RegisterModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<LoginModel> logger,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_emailSender = emailSender;
}
[BindProperty]
public InputModel Input { get; set; }
@ -54,17 +39,41 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
public string ConfirmPassword { get; set; }
}
public void OnGet(string returnUrl = null)
public virtual void OnGet(string returnUrl = null) => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync(string returnUrl = null) => throw new NotImplementedException();
}
internal class RegisterModel<TUser> : RegisterModel where TUser : IdentityUser, new()
{
private readonly SignInManager<TUser> _signInManager;
private readonly UserManager<TUser> _userManager;
private readonly ILogger<LoginModel> _logger;
private readonly IEmailSender _emailSender;
public RegisterModel(
UserManager<TUser> userManager,
SignInManager<TUser> signInManager,
ILogger<LoginModel> logger,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_emailSender = emailSender;
}
public override void OnGet(string returnUrl = null)
{
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
public override async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
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, Input.Password);
if (result.Succeeded)
{

View File

@ -7,17 +7,11 @@ 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 ResetPasswordModel : PageModel
[IdentityDefaultUI(typeof(ResetPasswordModel<>))]
public abstract class ResetPasswordModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
public ResetPasswordModel(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
[BindProperty]
public InputModel Input { get; set; }
@ -38,6 +32,20 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account
public string ConfirmPassword { get; set; }
public string Code { get; set; }
public virtual IActionResult OnGet(string code = null) => throw new NotImplementedException();
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
}
}
internal class ResetPasswordModel<TUser> : ResetPasswordModel where TUser : IdentityUser
{
private readonly UserManager<TUser> _userManager;
public ResetPasswordModel(UserManager<TUser> userManager)
{
_userManager = userManager;
}
public IActionResult OnGet(string code = null)

View File

@ -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 ResetPasswordConfirmationModel : PageModel
{

View File

@ -1 +1 @@
@using Microsoft.AspNetCore.Identity.UI.Pages.Account
@using Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal

View File

@ -1,2 +1,2 @@
@namespace Microsoft.AspNetCore.Identity.UI.Pages
@namespace Microsoft.AspNetCore.Identity.UI.Pages.Internal
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -33,7 +33,9 @@ namespace Microsoft.AspNetCore.Identity
{
AddAdditionalApplicationParts(builder);
builder.Services.ConfigureOptions<IdentityDefaultUIConfigureOptions>();
builder.Services.ConfigureOptions(
typeof(IdentityDefaultUIConfigureOptions<>)
.MakeGenericType(builder.UserType));
builder.Services.TryAddTransient<IEmailSender, EmailSender>();
return builder;

View File

@ -0,0 +1,18 @@
// 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;
namespace Microsoft.AspNetCore.Identity.UI
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
internal sealed class IdentityDefaultUIAttribute : Attribute
{
public IdentityDefaultUIAttribute(Type implementationTemplate)
{
Template = implementationTemplate;
}
public Type Template { get; }
}
}

View File

@ -5,6 +5,7 @@ using System;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.UI.Areas.Identity.Filters;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
@ -13,10 +14,10 @@ using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Identity.UI
{
internal class IdentityDefaultUIConfigureOptions :
internal class IdentityDefaultUIConfigureOptions<TUser> :
IPostConfigureOptions<RazorPagesOptions>,
IPostConfigureOptions<StaticFileOptions>,
IPostConfigureOptions<CookieAuthenticationOptions>
IPostConfigureOptions<CookieAuthenticationOptions> where TUser : IdentityUser
{
private const string IdentityUIDefaultAreaName = "Identity";
@ -35,6 +36,15 @@ namespace Microsoft.AspNetCore.Identity.UI
options.AllowAreas = true;
options.Conventions.AuthorizeAreaFolder(IdentityUIDefaultAreaName, "/Account/Manage");
options.Conventions.AuthorizeAreaPage(IdentityUIDefaultAreaName, "/Account/Logout");
var convention = new IdentityPageModelConvention<TUser>();
options.Conventions.AddAreaFolderApplicationModelConvention(
IdentityUIDefaultAreaName,
"/",
pam => convention.Apply(pam));
options.Conventions.AddAreaFolderApplicationModelConvention(
IdentityUIDefaultAreaName,
"/Account/Manage",
pam => pam.Filters.Add(new ExternalLoginsPageFilter<TUser>()));
}
public void PostConfigure(string name, StaticFileOptions options)

View File

@ -0,0 +1,43 @@
// 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.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace Microsoft.AspNetCore.Identity.UI
{
internal class IdentityPageModelConvention<TUser> : IPageApplicationModelConvention where TUser : IdentityUser
{
public void Apply(PageApplicationModel model)
{
var defaultUIAttribute = model.ModelType.GetCustomAttribute<IdentityDefaultUIAttribute>();
if (defaultUIAttribute == null)
{
return;
}
ValidateTemplate(defaultUIAttribute.Template);
var templateInstance = defaultUIAttribute.Template.MakeGenericType(typeof(TUser));
model.ModelType = templateInstance.GetTypeInfo();
}
private void ValidateTemplate(Type template)
{
if(template.IsAbstract || !template.IsGenericTypeDefinition)
{
throw new InvalidOperationException("Implementation type can't be abstract or non generic.");
}
var genericArguments = template.GetGenericArguments();
if (genericArguments.Length != 1)
{
throw new InvalidOperationException("Implementation type contains wrong generic arity.");
}
var argument = genericArguments[0];
if (!typeof(IdentityUser).IsAssignableFrom(typeof(TUser)))
{
throw new InvalidOperationException("Generic implementation type is not compatible.");
};
}
}
}