Identity: Add new email/confirmation flows (#8577)
This commit is contained in:
parent
8274776efa
commit
555b506a97
|
|
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
}
|
||||
public partial class SignInManager<TUser> where TUser : class
|
||||
{
|
||||
public SignInManager(Microsoft.AspNetCore.Identity.UserManager<TUser> userManager, Microsoft.AspNetCore.Http.IHttpContextAccessor contextAccessor, Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<TUser> claimsFactory, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Identity.IdentityOptions> optionsAccessor, Microsoft.Extensions.Logging.ILogger<Microsoft.AspNetCore.Identity.SignInManager<TUser>> logger, Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider schemes) { }
|
||||
public SignInManager(Microsoft.AspNetCore.Identity.UserManager<TUser> userManager, Microsoft.AspNetCore.Http.IHttpContextAccessor contextAccessor, Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<TUser> claimsFactory, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Identity.IdentityOptions> optionsAccessor, Microsoft.Extensions.Logging.ILogger<Microsoft.AspNetCore.Identity.SignInManager<TUser>> logger, Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider schemes, Microsoft.AspNetCore.Identity.IUserConfirmation<TUser> confirmation) { }
|
||||
public Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<TUser> ClaimsFactory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public Microsoft.AspNetCore.Http.HttpContext Context { get { throw null; } set { } }
|
||||
public virtual Microsoft.Extensions.Logging.ILogger Logger { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
|
||||
services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
|
||||
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
|
||||
services.TryAddScoped<IUserConfirmation<TUser>, DefaultUserConfirmation<TUser>>();
|
||||
services.TryAddScoped<UserManager<TUser>>();
|
||||
services.TryAddScoped<SignInManager<TUser>>();
|
||||
services.TryAddScoped<RoleManager<TRole>>();
|
||||
|
|
|
|||
|
|
@ -31,12 +31,14 @@ namespace Microsoft.AspNetCore.Identity
|
|||
/// <param name="optionsAccessor">The accessor used to access the <see cref="IdentityOptions"/>.</param>
|
||||
/// <param name="logger">The logger used to log messages, warnings and errors.</param>
|
||||
/// <param name="schemes">The scheme provider that is used enumerate the authentication schemes.</param>
|
||||
/// <param name="confirmation">The <see cref="IUserConfirmation{TUser}"/> used check whether a user account is confirmed.</param>
|
||||
public SignInManager(UserManager<TUser> userManager,
|
||||
IHttpContextAccessor contextAccessor,
|
||||
IUserClaimsPrincipalFactory<TUser> claimsFactory,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
ILogger<SignInManager<TUser>> logger,
|
||||
IAuthenticationSchemeProvider schemes)
|
||||
IAuthenticationSchemeProvider schemes,
|
||||
IUserConfirmation<TUser> confirmation)
|
||||
{
|
||||
if (userManager == null)
|
||||
{
|
||||
|
|
@ -57,11 +59,13 @@ namespace Microsoft.AspNetCore.Identity
|
|||
Options = optionsAccessor?.Value ?? new IdentityOptions();
|
||||
Logger = logger;
|
||||
_schemes = schemes;
|
||||
_confirmation = confirmation;
|
||||
}
|
||||
|
||||
private readonly IHttpContextAccessor _contextAccessor;
|
||||
private HttpContext _context;
|
||||
private IAuthenticationSchemeProvider _schemes;
|
||||
private IUserConfirmation<TUser> _confirmation;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ILogger"/> used to log messages from the manager.
|
||||
|
|
@ -148,7 +152,11 @@ namespace Microsoft.AspNetCore.Identity
|
|||
Logger.LogWarning(1, "User {userId} cannot sign in without a confirmed phone number.", await UserManager.GetUserIdAsync(user));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Options.SignIn.RequireConfirmedAccount && !(await _confirmation.IsConfirmedAsync(UserManager, user)))
|
||||
{
|
||||
Logger.LogWarning(4, "User {userId} cannot sign in without a confirmed account.", await UserManager.GetUserIdAsync(user));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ namespace Microsoft.AspNetCore.Identity
|
|||
public virtual string Protect(string data) { throw null; }
|
||||
public virtual string Unprotect(string data) { throw null; }
|
||||
}
|
||||
public partial class DefaultUserConfirmation<TUser> : Microsoft.AspNetCore.Identity.IUserConfirmation<TUser> where TUser : class
|
||||
{
|
||||
public DefaultUserConfirmation() { }
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
public virtual System.Threading.Tasks.Task<bool> IsConfirmedAsync(Microsoft.AspNetCore.Identity.UserManager<TUser> manager, TUser user) { throw null; }
|
||||
}
|
||||
public partial class EmailTokenProvider<TUser> : Microsoft.AspNetCore.Identity.TotpSecurityStampBasedTokenProvider<TUser> where TUser : class
|
||||
{
|
||||
public EmailTokenProvider() { }
|
||||
|
|
@ -194,6 +200,10 @@ namespace Microsoft.AspNetCore.Identity
|
|||
System.Threading.Tasks.Task RemoveClaimsAsync(TUser user, System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> claims, System.Threading.CancellationToken cancellationToken);
|
||||
System.Threading.Tasks.Task ReplaceClaimAsync(TUser user, System.Security.Claims.Claim claim, System.Security.Claims.Claim newClaim, System.Threading.CancellationToken cancellationToken);
|
||||
}
|
||||
public partial interface IUserConfirmation<TUser> where TUser : class
|
||||
{
|
||||
System.Threading.Tasks.Task<bool> IsConfirmedAsync(Microsoft.AspNetCore.Identity.UserManager<TUser> manager, TUser user);
|
||||
}
|
||||
public partial interface IUserEmailStore<TUser> : Microsoft.AspNetCore.Identity.IUserStore<TUser>, System.IDisposable where TUser : class
|
||||
{
|
||||
System.Threading.Tasks.Task<TUser> FindByEmailAsync(string normalizedEmail, System.Threading.CancellationToken cancellationToken);
|
||||
|
|
@ -396,6 +406,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
public partial class SignInOptions
|
||||
{
|
||||
public SignInOptions() { }
|
||||
public bool RequireConfirmedAccount { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public bool RequireConfirmedEmail { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public bool RequireConfirmedPhoneNumber { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
// 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.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="IUserConfirmation{TUser}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser">The type encapsulating a user.</typeparam>
|
||||
public class DefaultUserConfirmation<TUser> : IUserConfirmation<TUser> where TUser : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the specified <paramref name="user"/> is confirmed.
|
||||
/// </summary>
|
||||
/// <param name="manager">The <see cref="UserManager{TUser}"/> that can be used to retrieve user properties.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the confirmation operation.</returns>
|
||||
public async virtual Task<bool> IsConfirmedAsync(UserManager<TUser> manager, TUser user)
|
||||
{
|
||||
if (!await manager.IsEmailConfirmedAsync(user))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// 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.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an abstraction for confirmation of user accounts.
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser">The type encapsulating a user.</typeparam>
|
||||
public interface IUserConfirmation<TUser> where TUser : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the specified <paramref name="user"/> is confirmed.
|
||||
/// </summary>
|
||||
/// <param name="manager">The <see cref="UserManager{TUser}"/> that can be used to retrieve user properties.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>Whether the user is confirmed.</returns>
|
||||
Task<bool> IsConfirmedAsync(UserManager<TUser> manager, TUser user);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
|
||||
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
|
||||
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
|
||||
services.TryAddScoped<IUserConfirmation<TUser>, DefaultUserConfirmation<TUser>>();
|
||||
// No interface for the error describer so we can add errors without rev'ing the interface
|
||||
services.TryAddScoped<IdentityErrorDescriber>();
|
||||
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser>>();
|
||||
|
|
|
|||
|
|
@ -19,5 +19,11 @@ namespace Microsoft.AspNetCore.Identity
|
|||
/// </summary>
|
||||
/// <value>True if a user must have a confirmed telephone number before they can sign in, otherwise false.</value>
|
||||
public bool RequireConfirmedPhoneNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag indicating whether a confirmed <see cref="IUserConfirmation{TUser}"/> account is required to sign in. Defaults to false.
|
||||
/// </summary>
|
||||
/// <value>True if a user must have a confirmed account before they can sign in, otherwise false.</value>
|
||||
public bool RequireConfirmedAccount { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1710,6 +1710,34 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanChangeEmailOnlyIfEmailSame()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateManager();
|
||||
var user = CreateTestUser("foouser");
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var email = await manager.GetUserNameAsync(user) + "@diddly.bop";
|
||||
IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email));
|
||||
Assert.False(await manager.IsEmailConfirmedAsync(user));
|
||||
var stamp = await manager.GetSecurityStampAsync(user);
|
||||
var newEmail = await manager.GetUserNameAsync(user) + "@en.vec";
|
||||
var token1 = await manager.GenerateChangeEmailTokenAsync(user, newEmail);
|
||||
var token2 = await manager.GenerateChangeEmailTokenAsync(user, "should@fail.com");
|
||||
IdentityResultAssert.IsSuccess(await manager.ChangeEmailAsync(user, newEmail, token1));
|
||||
Assert.True(await manager.IsEmailConfirmedAsync(user));
|
||||
Assert.Equal(await manager.GetEmailAsync(user), newEmail);
|
||||
Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user));
|
||||
IdentityResultAssert.IsFailure(await manager.ChangeEmailAsync(user, "should@fail.com", token2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -37,9 +37,19 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
public void OnGet() { }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
public abstract partial class ConfirmEmailChangeModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected ConfirmEmailChangeModel() { }
|
||||
[Microsoft.AspNetCore.Mvc.TempDataAttribute]
|
||||
public string StatusMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string userId, string email, string code) { throw null; }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
public abstract partial class ConfirmEmailModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected ConfirmEmailModel() { }
|
||||
[Microsoft.AspNetCore.Mvc.TempDataAttribute]
|
||||
public string StatusMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string userId, string code) { throw null; }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
|
|
@ -103,6 +113,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
public string ReturnUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task OnGetAsync(string returnUrl = null) { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync(string returnUrl = null) { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostSendVerificationEmailAsync() { throw null; }
|
||||
public partial class InputModel
|
||||
{
|
||||
public InputModel() { }
|
||||
|
|
@ -165,6 +176,15 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPost(string returnUrl = null) { throw null; }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
public partial class RegisterConfirmationModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
public RegisterConfirmationModel() { }
|
||||
public bool DisplayConfirmAccountLink { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string EmailConfirmationUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string email) { throw null; }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected RegisterModel() { }
|
||||
|
|
@ -284,6 +304,27 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
public virtual Microsoft.AspNetCore.Mvc.IActionResult OnGet() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync() { throw null; }
|
||||
}
|
||||
public abstract partial class EmailModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected EmailModel() { }
|
||||
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[Microsoft.AspNetCore.Mvc.BindPropertyAttribute]
|
||||
public Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal.EmailModel.InputModel Input { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public bool IsEmailConfirmed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[Microsoft.AspNetCore.Mvc.TempDataAttribute]
|
||||
public string StatusMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostSendVerificationEmailAsync() { throw null; }
|
||||
public partial class InputModel
|
||||
{
|
||||
public InputModel() { }
|
||||
[System.ComponentModel.DataAnnotations.DisplayAttribute(Name="New email")]
|
||||
[System.ComponentModel.DataAnnotations.EmailAddressAttribute]
|
||||
[System.ComponentModel.DataAnnotations.RequiredAttribute]
|
||||
public string NewEmail { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
}
|
||||
}
|
||||
public partial class EnableAuthenticatorModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
public EnableAuthenticatorModel() { }
|
||||
|
|
@ -335,19 +376,14 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
protected IndexModel() { }
|
||||
[Microsoft.AspNetCore.Mvc.BindPropertyAttribute]
|
||||
public Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal.IndexModel.InputModel Input { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public bool IsEmailConfirmed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[Microsoft.AspNetCore.Mvc.TempDataAttribute]
|
||||
public string StatusMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string Username { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostSendVerificationEmailAsync() { throw null; }
|
||||
public partial class InputModel
|
||||
{
|
||||
public InputModel() { }
|
||||
[System.ComponentModel.DataAnnotations.EmailAddressAttribute]
|
||||
[System.ComponentModel.DataAnnotations.RequiredAttribute]
|
||||
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[System.ComponentModel.DataAnnotations.DisplayAttribute(Name="Phone number")]
|
||||
[System.ComponentModel.DataAnnotations.PhoneAttribute]
|
||||
public string PhoneNumber { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
|
|
@ -358,6 +394,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
public static string ChangePassword { get { throw null; } }
|
||||
public static string DeletePersonalData { get { throw null; } }
|
||||
public static string DownloadPersonalData { get { throw null; } }
|
||||
public static string Email { get { throw null; } }
|
||||
public static string ExternalLogins { get { throw null; } }
|
||||
public static string Index { get { throw null; } }
|
||||
public static string PersonalData { get { throw null; } }
|
||||
|
|
@ -365,6 +402,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
public static string ChangePasswordNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string DeletePersonalDataNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string DownloadPersonalDataNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string EmailNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string ExternalLoginsNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string IndexNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string PageNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext, string page) { throw null; }
|
||||
|
|
@ -450,9 +488,19 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
public void OnGet() { }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
public abstract partial class ConfirmEmailChangeModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected ConfirmEmailChangeModel() { }
|
||||
[Microsoft.AspNetCore.Mvc.TempDataAttribute]
|
||||
public string StatusMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string userId, string email, string code) { throw null; }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
public abstract partial class ConfirmEmailModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected ConfirmEmailModel() { }
|
||||
[Microsoft.AspNetCore.Mvc.TempDataAttribute]
|
||||
public string StatusMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string userId, string code) { throw null; }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
|
|
@ -578,6 +626,15 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPost(string returnUrl = null) { throw null; }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
public partial class RegisterConfirmationModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
public RegisterConfirmationModel() { }
|
||||
public bool DisplayConfirmAccountLink { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string EmailConfirmationUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync(string email) { throw null; }
|
||||
}
|
||||
[Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute]
|
||||
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected RegisterModel() { }
|
||||
|
|
@ -697,6 +754,27 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
public virtual Microsoft.AspNetCore.Mvc.IActionResult OnGet() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync() { throw null; }
|
||||
}
|
||||
public abstract partial class EmailModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected EmailModel() { }
|
||||
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[Microsoft.AspNetCore.Mvc.BindPropertyAttribute]
|
||||
public Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal.EmailModel.InputModel Input { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public bool IsEmailConfirmed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[Microsoft.AspNetCore.Mvc.TempDataAttribute]
|
||||
public string StatusMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostSendVerificationEmailAsync() { throw null; }
|
||||
public partial class InputModel
|
||||
{
|
||||
public InputModel() { }
|
||||
[System.ComponentModel.DataAnnotations.DisplayAttribute(Name="New email")]
|
||||
[System.ComponentModel.DataAnnotations.EmailAddressAttribute]
|
||||
[System.ComponentModel.DataAnnotations.RequiredAttribute]
|
||||
public string NewEmail { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
}
|
||||
}
|
||||
public partial class EnableAuthenticatorModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
public EnableAuthenticatorModel() { }
|
||||
|
|
@ -748,19 +826,14 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
protected IndexModel() { }
|
||||
[Microsoft.AspNetCore.Mvc.BindPropertyAttribute]
|
||||
public Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal.IndexModel.InputModel Input { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public bool IsEmailConfirmed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[Microsoft.AspNetCore.Mvc.TempDataAttribute]
|
||||
public string StatusMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string Username { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnGetAsync() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync() { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostSendVerificationEmailAsync() { throw null; }
|
||||
public partial class InputModel
|
||||
{
|
||||
public InputModel() { }
|
||||
[System.ComponentModel.DataAnnotations.EmailAddressAttribute]
|
||||
[System.ComponentModel.DataAnnotations.RequiredAttribute]
|
||||
public string Email { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[System.ComponentModel.DataAnnotations.DisplayAttribute(Name="Phone number")]
|
||||
[System.ComponentModel.DataAnnotations.PhoneAttribute]
|
||||
public string PhoneNumber { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
|
|
@ -771,6 +844,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
public static string ChangePassword { get { throw null; } }
|
||||
public static string DeletePersonalData { get { throw null; } }
|
||||
public static string DownloadPersonalData { get { throw null; } }
|
||||
public static string Email { get { throw null; } }
|
||||
public static string ExternalLogins { get { throw null; } }
|
||||
public static string Index { get { throw null; } }
|
||||
public static string PersonalData { get { throw null; } }
|
||||
|
|
@ -778,6 +852,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
public static string ChangePasswordNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string DeletePersonalDataNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string DownloadPersonalDataNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string EmailNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string ExternalLoginsNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string IndexNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext) { throw null; }
|
||||
public static string PageNavClass(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext, string page) { throw null; }
|
||||
|
|
|
|||
|
|
@ -5,8 +5,4 @@
|
|||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<div>
|
||||
<p>
|
||||
Thank you for confirming your email.
|
||||
</p>
|
||||
</div>
|
||||
<partial name="_StatusMessage" model="Model.StatusMessage" />
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
|
|
@ -18,6 +17,13 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
[IdentityDefaultUI(typeof(ConfirmEmailModel<>))]
|
||||
public abstract class ConfirmEmailModel : PageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -48,11 +54,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
}
|
||||
|
||||
var result = await _userManager.ConfirmEmailAsync(user, code);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
throw new InvalidOperationException($"Error confirming email for user with ID '{userId}':");
|
||||
}
|
||||
|
||||
StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email.";
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
@page
|
||||
@model ConfirmEmailChangeModel
|
||||
@{
|
||||
ViewData["Title"] = "Confirm email change";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<partial name="_StatusMessage" model="Model.StatusMessage" />
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
// 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.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[IdentityDefaultUI(typeof(ConfirmEmailChangeModel<>))]
|
||||
public abstract class ConfirmEmailChangeModel : PageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnGetAsync(string userId, string email, string code) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class ConfirmEmailChangeModel<TUser> : ConfirmEmailChangeModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly SignInManager<TUser> _signInManager;
|
||||
|
||||
public ConfirmEmailChangeModel(UserManager<TUser> userManager, SignInManager<TUser> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnGetAsync(string userId, string email, string code)
|
||||
{
|
||||
if (userId == null || email == null || code == null)
|
||||
{
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
|
||||
var user = await _userManager.FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{userId}'.");
|
||||
}
|
||||
|
||||
var result = await _userManager.ChangeEmailAsync(user, email, code);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
StatusMessage = "Error changing email.";
|
||||
return Page();
|
||||
}
|
||||
|
||||
// In our UI email and user name are one and the same, so when we update the email
|
||||
// we need to update the user name.
|
||||
var setUserNameResult = await _userManager.SetUserNameAsync(user, email);
|
||||
if (!setUserNameResult.Succeeded)
|
||||
{
|
||||
StatusMessage = "Error changing user name.";
|
||||
return Page();
|
||||
}
|
||||
|
||||
await _signInManager.RefreshSignInAsync(user);
|
||||
StatusMessage = "Thank you for confirming your email change.";
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-default">Log in</button>
|
||||
<button id="login-submit" type="submit" class="btn btn-default">Log in</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<p>
|
||||
|
|
@ -41,6 +41,9 @@
|
|||
<p>
|
||||
<a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
|
||||
</p>
|
||||
<p>
|
||||
<button id="resend-confirmation" type="submit" asp-page-handler="SendVerificationEmail" class="btn-link" style="padding:0px;margin:0px;border:0px">Resend email confirmation</button>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -90,16 +92,28 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostAsync(string returnUrl = null) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostSendVerificationEmailAsync() => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class LoginModel<TUser> : LoginModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly SignInManager<TUser> _signInManager;
|
||||
private readonly ILogger<LoginModel> _logger;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public LoginModel(SignInManager<TUser> signInManager, ILogger<LoginModel> logger)
|
||||
public LoginModel(SignInManager<TUser> signInManager, ILogger<LoginModel> logger,
|
||||
UserManager<TUser> userManager,
|
||||
IEmailSender emailSender)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
|
@ -155,5 +169,34 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
// If we got this far, something failed, redisplay form
|
||||
return Page();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostSendVerificationEmailAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var user = await _userManager.FindByEmailAsync(Input.Email);
|
||||
if (user == null)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email.");
|
||||
}
|
||||
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, code = code },
|
||||
protocol: Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(
|
||||
Input.Email,
|
||||
"Confirm your email",
|
||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email.");
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
@page
|
||||
@model EmailModel
|
||||
@{
|
||||
ViewData["Title"] = "Manage Email";
|
||||
ViewData["ActivePage"] = ManageNavPages.Email;
|
||||
}
|
||||
|
||||
<h4>@ViewData["Title"]</h4>
|
||||
<partial name="_StatusMessage" model="Model.StatusMessage" />
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form id="email-form" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Email"></label>
|
||||
@if (Model.IsEmailConfirmed)
|
||||
{
|
||||
<div class="input-group">
|
||||
<input asp-for="Email" class="form-control" disabled />
|
||||
<span class="input-group-addon" aria-hidden="true"><span class="glyphicon glyphicon-ok text-success"></span></span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input asp-for="Email" class="form-control" disabled />
|
||||
<button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" class="btn btn-link">Send verification email</button>
|
||||
}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.NewEmail"></label>
|
||||
<input asp-for="Input.NewEmail" class="form-control" />
|
||||
<span asp-validation-for="Input.NewEmail" class="text-danger"></span>
|
||||
</div>
|
||||
<button id="change-email-button" type="submit" class="btn btn-default">Change email</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
// 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 Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[IdentityDefaultUI(typeof(EmailModel<>))]
|
||||
public abstract class EmailModel : PageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public bool IsEmailConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[BindProperty]
|
||||
public InputModel Input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public class InputModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "New email")]
|
||||
public string NewEmail { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnGetAsync() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostSendVerificationEmailAsync() => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class EmailModel<TUser> : EmailModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly SignInManager<TUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public EmailModel(
|
||||
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)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
|
||||
Email = email;
|
||||
|
||||
Input = new InputModel
|
||||
{
|
||||
NewEmail = email,
|
||||
};
|
||||
|
||||
IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
if (Input.NewEmail != email)
|
||||
{
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail);
|
||||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmailChange",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, email = Input.NewEmail, code = code },
|
||||
protocol: Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(
|
||||
Input.NewEmail,
|
||||
"Confirm your email",
|
||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
StatusMessage = "Confirmation link to change email sent. Please check your email.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
StatusMessage = "Your email is unchanged.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostSendVerificationEmailAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, code = code },
|
||||
protocol: Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(
|
||||
email,
|
||||
"Confirm your email",
|
||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
StatusMessage = "Verification email sent. Please check your email.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,22 +15,6 @@
|
|||
<label asp-for="Username"></label>
|
||||
<input asp-for="Username" class="form-control" disabled />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.Email"></label>
|
||||
@if (Model.IsEmailConfirmed)
|
||||
{
|
||||
<div class="input-group">
|
||||
<input asp-for="Input.Email" class="form-control" />
|
||||
<span class="input-group-addon" aria-hidden="true"><span class="glyphicon glyphicon-ok text-success"></span></span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input asp-for="Input.Email" class="form-control" />
|
||||
<button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" class="btn btn-link">Send verification email</button>
|
||||
}
|
||||
<span asp-validation-for="Input.Email" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.PhoneNumber"></label>
|
||||
<input asp-for="Input.PhoneNumber" class="form-control" />
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
|
|
@ -24,12 +22,6 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public bool IsEmailConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -50,14 +42,6 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
/// </summary>
|
||||
public class InputModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -78,28 +62,19 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostSendVerificationEmailAsync() => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class IndexModel<TUser> : IndexModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly SignInManager<TUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public IndexModel(
|
||||
UserManager<TUser> userManager,
|
||||
SignInManager<TUser> signInManager,
|
||||
IEmailSender emailSender)
|
||||
SignInManager<TUser> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnGetAsync()
|
||||
|
|
@ -110,19 +85,15 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
var userName = await _userManager.GetUserNameAsync(user);
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
|
||||
|
||||
Username = userName;
|
||||
|
||||
Input = new InputModel
|
||||
{
|
||||
Email = email,
|
||||
PhoneNumber = phoneNumber
|
||||
};
|
||||
|
||||
IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
|
|
@ -139,26 +110,6 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
if (Input.Email != email)
|
||||
{
|
||||
var setEmailResult = await _userManager.SetEmailAsync(user, Input.Email);
|
||||
if (!setEmailResult.Succeeded)
|
||||
{
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
throw new InvalidOperationException($"Unexpected error occurred setting email for user with ID '{userId}'.");
|
||||
}
|
||||
|
||||
// In our UI email and user name are one and the same, so when we update the email
|
||||
// we need to update the user name.
|
||||
var setUserNameResult = await _userManager.SetUserNameAsync(user, Input.Email);
|
||||
if (!setUserNameResult.Succeeded)
|
||||
{
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
throw new InvalidOperationException($"Unexpected error occurred setting name for user with ID '{userId}'.");
|
||||
}
|
||||
}
|
||||
|
||||
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
|
||||
if (Input.PhoneNumber != phoneNumber)
|
||||
{
|
||||
|
|
@ -174,36 +125,5 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
StatusMessage = "Your profile has been updated";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostSendVerificationEmailAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, code = code },
|
||||
protocol: Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(
|
||||
email,
|
||||
"Confirm your email",
|
||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
StatusMessage = "Verification email sent. Please check your email.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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;
|
||||
|
|
@ -18,6 +18,12 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
/// </summary>
|
||||
public static string Index => "Index";
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public static string Email => "Email";
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -60,6 +66,12 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Manage.Internal
|
|||
/// </summary>
|
||||
public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index);
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public static string EmailNavClass(ViewContext viewContext) => PageNavClass(viewContext, Email);
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<ul class="nav nav-pills nav-stacked">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li class="@ManageNavPages.IndexNavClass(ViewContext)"><a id="profile" asp-page="./Index">Profile</a></li>
|
||||
<li class="@ManageNavPages.EmailNavClass(ViewContext)"><a id="email" asp-page="./Email">Email</a></li>
|
||||
<li class="@ManageNavPages.ChangePasswordNavClass(ViewContext)"><a id="change-password" asp-page="./ChangePassword">Password</a></li>
|
||||
@if ((bool)ViewData["ManageNav.HasExternalLogins"])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -150,8 +150,15 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
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);
|
||||
if (_userManager.Options.SignIn.RequireConfirmedAccount)
|
||||
{
|
||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
|
||||
}
|
||||
else
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return LocalRedirect(returnUrl);
|
||||
}
|
||||
}
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
@page
|
||||
@model RegisterConfirmationModel
|
||||
@{
|
||||
ViewData["Title"] = "Register confirmation";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
@{
|
||||
if (@Model.DisplayConfirmAccountLink)
|
||||
{
|
||||
<p>
|
||||
This app does not currently have a real email sender registered, see <a href="https://aka.ms/aspaccountconf">these docs</a> for how to configure a real email sender.
|
||||
Normally this would be emailed: <a id="confirm-link" href="@Model.EmailConfirmationUrl">Click here to confirm your account</a>
|
||||
</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>
|
||||
Please check your email to confirm your account.
|
||||
</p>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// 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.Authorization;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[IdentityDefaultUI(typeof(RegisterConfirmationModel<>))]
|
||||
public class RegisterConfirmationModel : PageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public bool DisplayConfirmAccountLink { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public string EmailConfirmationUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnGetAsync(string email) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class RegisterConfirmationModel<TUser> : RegisterConfirmationModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly IWebHostEnvironment _hostingEnv;
|
||||
private readonly IEmailSender _sender;
|
||||
|
||||
public RegisterConfirmationModel(UserManager<TUser> userManager, IWebHostEnvironment hostingEnv, IEmailSender sender)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_hostingEnv = hostingEnv;
|
||||
_sender = sender;
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnGetAsync(string email)
|
||||
{
|
||||
if (email == null)
|
||||
{
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
|
||||
var user = await _userManager.FindByEmailAsync(email);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with email '{email}'.");
|
||||
}
|
||||
|
||||
Email = email;
|
||||
// If the email sender is a no-op, display the confirm link in the page
|
||||
DisplayConfirmAccountLink = _sender is EmailSender;
|
||||
if (DisplayConfirmAccountLink)
|
||||
{
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
EmailConfirmationUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, code = code },
|
||||
protocol: Request.Scheme);
|
||||
}
|
||||
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
@model string
|
||||
|
||||
@if (!String.IsNullOrEmpty(Model))
|
||||
{
|
||||
var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success";
|
||||
<div class="alert alert-@statusMessageClass alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
@Model
|
||||
</div>
|
||||
}
|
||||
|
|
@ -5,8 +5,3 @@
|
|||
}
|
||||
|
||||
<h1>@ViewData["Title"]</h1>
|
||||
<div>
|
||||
<p>
|
||||
Thank you for confirming your email.
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,13 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
[IdentityDefaultUI(typeof(ConfirmEmailModel<>))]
|
||||
public abstract class ConfirmEmailModel : PageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -47,11 +54,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
}
|
||||
|
||||
var result = await _userManager.ConfirmEmailAsync(user, code);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
throw new InvalidOperationException($"Error confirming email for user with ID '{userId}':");
|
||||
}
|
||||
|
||||
StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email.";
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
@page
|
||||
@model ConfirmEmailChangeModel
|
||||
@{
|
||||
ViewData["Title"] = "Confirm email change";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<partial name="_StatusMessage" model="Model.StatusMessage" />
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
// 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.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[IdentityDefaultUI(typeof(ConfirmEmailChangeModel<>))]
|
||||
public abstract class ConfirmEmailChangeModel : PageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnGetAsync(string userId, string email, string code) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class ConfirmEmailChangeModel<TUser> : ConfirmEmailChangeModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly SignInManager<TUser> _signInManager;
|
||||
|
||||
public ConfirmEmailChangeModel(UserManager<TUser> userManager, SignInManager<TUser> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnGetAsync(string userId, string email, string code)
|
||||
{
|
||||
if (userId == null || email == null || code == null)
|
||||
{
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
|
||||
var user = await _userManager.FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{userId}'.");
|
||||
}
|
||||
|
||||
var result = await _userManager.ChangeEmailAsync(user, email, code);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
StatusMessage = "Error changing email.";
|
||||
return Page();
|
||||
}
|
||||
|
||||
// In our UI email and user name are one and the same, so when we update the email
|
||||
// we need to update the user name.
|
||||
var setUserNameResult = await _userManager.SetUserNameAsync(user, email);
|
||||
if (!setUserNameResult.Succeeded)
|
||||
{
|
||||
StatusMessage = "Error changing user name.";
|
||||
return Page();
|
||||
}
|
||||
|
||||
await _signInManager.RefreshSignInAsync(user);
|
||||
StatusMessage = "Thank you for confirming your email change.";
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">Log in</button>
|
||||
<button id="login-submit" type="submit" class="btn btn-primary">Log in</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
@page
|
||||
@model EmailModel
|
||||
@{
|
||||
ViewData["Title"] = "Manage Email";
|
||||
ViewData["ActivePage"] = ManageNavPages.Email;
|
||||
}
|
||||
|
||||
<h4>@ViewData["Title"]</h4>
|
||||
<partial name="_StatusMessage" for="StatusMessage" />
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form id="email-form" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Email"></label>
|
||||
@if (Model.IsEmailConfirmed)
|
||||
{
|
||||
<div class="input-group">
|
||||
<input asp-for="Email" class="form-control" disabled />
|
||||
<span class="input-group-addon" aria-hidden="true"><span class="glyphicon glyphicon-ok text-success"></span></span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input asp-for="Email" class="form-control" disabled />
|
||||
<button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" class="btn btn-link">Send verification email</button>
|
||||
}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.NewEmail"></label>
|
||||
<input asp-for="Input.NewEmail" class="form-control" />
|
||||
<span asp-validation-for="Input.NewEmail" class="text-danger"></span>
|
||||
</div>
|
||||
<button id="change-email-button" type="submit" class="btn btn-default">Change email</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
// 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 Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[IdentityDefaultUI(typeof(EmailModel<>))]
|
||||
public abstract class EmailModel : PageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public bool IsEmailConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[BindProperty]
|
||||
public InputModel Input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public class InputModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "New email")]
|
||||
public string NewEmail { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnGetAsync() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostSendVerificationEmailAsync() => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class EmailModel<TUser> : EmailModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly SignInManager<TUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public EmailModel(
|
||||
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)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
|
||||
Email = email;
|
||||
|
||||
Input = new InputModel
|
||||
{
|
||||
NewEmail = email,
|
||||
};
|
||||
|
||||
IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
if (Input.NewEmail != email)
|
||||
{
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail);
|
||||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmailChange",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, email = Input.NewEmail, code = code },
|
||||
protocol: Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(
|
||||
Input.NewEmail,
|
||||
"Confirm your email",
|
||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
StatusMessage = "Confirmation link to change email sent. Please check your email.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
StatusMessage = "Your email is unchanged.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostSendVerificationEmailAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, code = code },
|
||||
protocol: Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(
|
||||
email,
|
||||
"Confirm your email",
|
||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
StatusMessage = "Verification email sent. Please check your email.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,22 +15,6 @@
|
|||
<label asp-for="Username"></label>
|
||||
<input asp-for="Username" class="form-control" disabled />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.Email"></label>
|
||||
@if (Model.IsEmailConfirmed)
|
||||
{
|
||||
<div class="input-group">
|
||||
<input asp-for="Input.Email" class="form-control" />
|
||||
<span class="input-group-addon" aria-hidden="true"><span class="glyphicon glyphicon-ok text-success"></span></span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input asp-for="Input.Email" class="form-control" />
|
||||
<button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" class="btn btn-link">Send verification email</button>
|
||||
}
|
||||
<span asp-validation-for="Input.Email" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.PhoneNumber"></label>
|
||||
<input asp-for="Input.PhoneNumber" class="form-control" />
|
||||
|
|
|
|||
|
|
@ -24,12 +24,6 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public bool IsEmailConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -50,14 +44,6 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
/// </summary>
|
||||
public class InputModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -78,28 +64,19 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostAsync() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnPostSendVerificationEmailAsync() => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class IndexModel<TUser> : IndexModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly SignInManager<TUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public IndexModel(
|
||||
UserManager<TUser> userManager,
|
||||
SignInManager<TUser> signInManager,
|
||||
IEmailSender emailSender)
|
||||
SignInManager<TUser> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnGetAsync()
|
||||
|
|
@ -110,19 +87,15 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
var userName = await _userManager.GetUserNameAsync(user);
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
|
||||
|
||||
Username = userName;
|
||||
|
||||
Input = new InputModel
|
||||
{
|
||||
Email = email,
|
||||
PhoneNumber = phoneNumber
|
||||
};
|
||||
|
||||
IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
|
|
@ -139,26 +112,6 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
if (Input.Email != email)
|
||||
{
|
||||
var setEmailResult = await _userManager.SetEmailAsync(user, Input.Email);
|
||||
if (!setEmailResult.Succeeded)
|
||||
{
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
throw new InvalidOperationException($"Unexpected error occurred setting email for user with ID '{userId}'.");
|
||||
}
|
||||
|
||||
// In our UI email and user name are one and the same, so when we update the email
|
||||
// we need to update the user name.
|
||||
var setUserNameResult = await _userManager.SetUserNameAsync(user, Input.Email);
|
||||
if (!setUserNameResult.Succeeded)
|
||||
{
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
throw new InvalidOperationException($"Unexpected error occurred setting name for user with ID '{userId}'.");
|
||||
}
|
||||
}
|
||||
|
||||
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
|
||||
if (Input.PhoneNumber != phoneNumber)
|
||||
{
|
||||
|
|
@ -174,36 +127,5 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
StatusMessage = "Your profile has been updated";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostSendVerificationEmailAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||
}
|
||||
|
||||
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var callbackUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, code = code },
|
||||
protocol: Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(
|
||||
email,
|
||||
"Confirm your email",
|
||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
StatusMessage = "Verification email sent. Please check your email.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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;
|
||||
|
|
@ -18,6 +18,12 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
/// </summary>
|
||||
public static string Index => "Index";
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public static string Email => "Email";
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -60,6 +66,12 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal
|
|||
/// </summary>
|
||||
public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index);
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public static string EmailNavClass(ViewContext viewContext) => PageNavClass(viewContext, Email);
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<ul class="nav nav-pills flex-column">
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item"><a class="nav-link @ManageNavPages.IndexNavClass(ViewContext)" id="profile" asp-page="./Index">Profile</a></li>
|
||||
<li class="nav-item"><a class="nav-link @ManageNavPages.EmailNavClass(ViewContext)" id="email" asp-page="./Email">Email</a></li>
|
||||
<li class="nav-item"><a class="nav-link @ManageNavPages.ChangePasswordNavClass(ViewContext)" id="change-password" asp-page="./ChangePassword">Password</a></li>
|
||||
@if ((bool)ViewData["ManageNav.HasExternalLogins"])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -149,8 +149,15 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
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);
|
||||
if (_userManager.Options.SignIn.RequireConfirmedAccount)
|
||||
{
|
||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
|
||||
}
|
||||
else
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return LocalRedirect(returnUrl);
|
||||
}
|
||||
}
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
@page
|
||||
@model RegisterConfirmationModel
|
||||
@{
|
||||
ViewData["Title"] = "Register confirmation";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
@{
|
||||
if (@Model.DisplayConfirmAccountLink)
|
||||
{
|
||||
<p>
|
||||
This app does not currently have a real email sender registered, see <a href="https://aka.ms/aspaccountconf">these docs</a> for how to configure a real email sender.
|
||||
Normally this would be emailed: <a id="confirm-link" href="@Model.EmailConfirmationUrl">Click here to confirm your account</a>
|
||||
</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>
|
||||
Please check your email to confirm your account.
|
||||
</p>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// 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.Authorization;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[IdentityDefaultUI(typeof(RegisterConfirmationModel<>))]
|
||||
public class RegisterConfirmationModel : PageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public bool DisplayConfirmAccountLink { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public string EmailConfirmationUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual Task<IActionResult> OnGetAsync(string email) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal class RegisterConfirmationModel<TUser> : RegisterConfirmationModel where TUser : class
|
||||
{
|
||||
private readonly UserManager<TUser> _userManager;
|
||||
private readonly IWebHostEnvironment _hostingEnv;
|
||||
private readonly IEmailSender _sender;
|
||||
|
||||
public RegisterConfirmationModel(UserManager<TUser> userManager, IWebHostEnvironment hostingEnv, IEmailSender sender)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_hostingEnv = hostingEnv;
|
||||
_sender = sender;
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnGetAsync(string email)
|
||||
{
|
||||
if (email == null)
|
||||
{
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
|
||||
var user = await _userManager.FindByEmailAsync(email);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound($"Unable to load user with email '{email}'.");
|
||||
}
|
||||
|
||||
Email = email;
|
||||
// This sender is a no-op, so we should auto confirm the account
|
||||
DisplayConfirmAccountLink = _sender is EmailSender;
|
||||
if (DisplayConfirmAccountLink)
|
||||
{
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
EmailConfirmationUrl = Url.Page(
|
||||
"/Account/ConfirmEmail",
|
||||
pageHandler: null,
|
||||
values: new { userId = userId, code = code },
|
||||
protocol: Request.Scheme);
|
||||
|
||||
}
|
||||
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
@model string
|
||||
|
||||
@if (!String.IsNullOrEmpty(Model))
|
||||
{
|
||||
var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success";
|
||||
<div class="alert alert-@statusMessageClass alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
@Model
|
||||
</div>
|
||||
}
|
||||
|
|
@ -22,22 +22,6 @@
|
|||
<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" />
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@
|
|||
|
||||
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;
|
||||
|
||||
|
|
@ -17,22 +15,17 @@ namespace IdentitySample.DefaultUI
|
|||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public IndexModel(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IEmailSender emailSender)
|
||||
SignInManager<ApplicationUser> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public bool IsEmailConfirmed { get; set; }
|
||||
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
|
|
@ -41,10 +34,6 @@ namespace IdentitySample.DefaultUI
|
|||
|
||||
public class InputModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Phone]
|
||||
[Display(Name = "Phone number")]
|
||||
public string PhoneNumber { get; set; }
|
||||
|
|
@ -73,12 +62,9 @@ namespace IdentitySample.DefaultUI
|
|||
{
|
||||
Name = user.Name,
|
||||
Age = user.Age,
|
||||
Email = user.Email,
|
||||
PhoneNumber = user.PhoneNumber
|
||||
};
|
||||
|
||||
IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
|
|
@ -111,15 +97,6 @@ namespace IdentitySample.DefaultUI
|
|||
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);
|
||||
|
|
@ -133,33 +110,5 @@ namespace IdentitySample.DefaultUI
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,8 +106,15 @@ namespace IdentitySample.DefaultUI
|
|||
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);
|
||||
if (_userManager.Options.SignIn.RequireConfirmedAccount)
|
||||
{
|
||||
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
|
||||
}
|
||||
else
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return LocalRedirect(returnUrl);
|
||||
}
|
||||
}
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Threading.Tasks;
|
||||
using IdentitySample.DefaultUI.Data;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
|
@ -11,6 +12,14 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace IdentitySample.DefaultUI
|
||||
{
|
||||
public class BadDude : IUserConfirmation<ApplicationUser>
|
||||
{
|
||||
public Task<bool> IsConfirmedAsync(UserManager<ApplicationUser> manager, ApplicationUser user)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IWebHostEnvironment env)
|
||||
|
|
@ -37,7 +46,7 @@ namespace IdentitySample.DefaultUI
|
|||
|
||||
services.AddMvc().AddNewtonsoftJson();
|
||||
|
||||
services.AddDefaultIdentity<ApplicationUser>()
|
||||
services.AddDefaultIdentity<ApplicationUser>(o => o.SignIn.RequireConfirmedAccount = true)
|
||||
.AddRoles<IdentityRole>()
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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;
|
||||
|
|
@ -35,6 +35,9 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
internal DefaultUIContext WithCookieConsent() =>
|
||||
new DefaultUIContext(this) { CookiePolicyAccepted = true };
|
||||
|
||||
internal DefaultUIContext WithRealEmailSender() =>
|
||||
new DefaultUIContext(this) { HasRealEmailSender = true };
|
||||
|
||||
public string AuthenticatorKey
|
||||
{
|
||||
get => GetValue<string>(nameof(AuthenticatorKey));
|
||||
|
|
@ -93,5 +96,11 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
get => GetValue<bool>(nameof(CookiePolicyAccepted));
|
||||
set => SetValue(nameof(CookiePolicyAccepted), value);
|
||||
}
|
||||
|
||||
public bool HasRealEmailSender
|
||||
{
|
||||
get => GetValue<bool>(nameof(HasRealEmailSender));
|
||||
set => SetValue(nameof(HasRealEmailSender), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,9 +70,9 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
void ConfigureTestServices(IServiceCollection services) =>
|
||||
services.SetupTestEmailSender(emails);
|
||||
|
||||
var client = ServerFactory
|
||||
.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices))
|
||||
.CreateClient();
|
||||
var server = ServerFactory
|
||||
.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices));
|
||||
var client = server.CreateClient();
|
||||
|
||||
var userName = $"{Guid.NewGuid()}@example.com";
|
||||
var password = $"!Test.Password1$";
|
||||
|
|
@ -91,21 +91,30 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
{
|
||||
// Arrange
|
||||
var emails = new ContosoEmailSender();
|
||||
var client = ServerFactory
|
||||
.CreateClient();
|
||||
void ConfigureTestServices(IServiceCollection services) =>
|
||||
services.SetupTestEmailSender(emails);
|
||||
|
||||
var server = ServerFactory
|
||||
.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices));
|
||||
var client = server.CreateClient();
|
||||
var newClient = server.CreateClient();
|
||||
var failedClient = server.CreateClient();
|
||||
|
||||
var userName = $"{Guid.NewGuid()}@example.com";
|
||||
var password = $"!Test.Password1$";
|
||||
var newEmail = "updatedEmail@example.com";
|
||||
|
||||
var index = await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||
var manageIndex = await UserStories.SendUpdateProfileAsync(index, newEmail);
|
||||
var email = await UserStories.SendUpdateEmailAsync(index, newEmail);
|
||||
|
||||
// Act & Assert
|
||||
var pageUserName = manageIndex.GetUserName();
|
||||
Assert.Equal(newEmail, pageUserName);
|
||||
var pageEmail = manageIndex.GetEmail();
|
||||
Assert.Equal(newEmail, pageEmail);
|
||||
Assert.Equal(2, emails.SentEmails.Count);
|
||||
await UserStories.ConfirmEmailAsync(emails.SentEmails[1], client);
|
||||
|
||||
// Verify can login with new email, fails with old
|
||||
await UserStories.LoginExistingUserAsync(newClient, newEmail, password);
|
||||
await UserStories.LoginFailsWithWrongPasswordAsync(failedClient, userName, password);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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.Net;
|
||||
|
|
@ -6,9 +6,7 @@ using System.Threading.Tasks;
|
|||
using Identity.DefaultUI.WebSite;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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.Collections.Generic;
|
||||
|
|
@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
private readonly IHtmlAnchorElement _forgotPasswordLink;
|
||||
private readonly IHtmlFormElement _externalLoginForm;
|
||||
private readonly IHtmlElement _contosoButton;
|
||||
private readonly IHtmlElement _loginButton;
|
||||
|
||||
public Login(
|
||||
HttpClient client,
|
||||
|
|
@ -23,6 +24,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
: base(client, login, context)
|
||||
{
|
||||
_loginForm = HtmlAssert.HasForm("#account", login);
|
||||
_loginButton = HtmlAssert.HasElement("#login-submit", login);
|
||||
_forgotPasswordLink = HtmlAssert.HasLink("#forgot-password", login);
|
||||
if (Context.ContosoLoginEnabled)
|
||||
{
|
||||
|
|
@ -87,7 +89,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
|
||||
private async Task<HttpResponseMessage> SendLoginForm(string userName, string password)
|
||||
{
|
||||
return await Client.SendAsync(_loginForm, new Dictionary<string, string>()
|
||||
return await Client.SendAsync(_loginForm, _loginButton, new Dictionary<string, string>()
|
||||
{
|
||||
["Input_Email"] = userName,
|
||||
["Input_Password"] = password
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
// 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.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class Email : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlElement _emailInput;
|
||||
private readonly IHtmlElement _newEmailInput;
|
||||
private readonly IHtmlElement _confirmEmailButton;
|
||||
private readonly IHtmlFormElement _changeEmailForm;
|
||||
private readonly IHtmlElement _changeEmailButton;
|
||||
|
||||
public static readonly string Path = "/";
|
||||
|
||||
public Email(HttpClient client, IHtmlDocument manage, DefaultUIContext context)
|
||||
: base(client, manage, context)
|
||||
{
|
||||
Assert.True(Context.UserAuthenticated);
|
||||
|
||||
_changeEmailForm = HtmlAssert.HasForm("#email-form", manage);
|
||||
_emailInput = HtmlAssert.HasElement("#Email", manage);
|
||||
_newEmailInput = HtmlAssert.HasElement("#Input_NewEmail", manage);
|
||||
_changeEmailButton = HtmlAssert.HasElement("#change-email-button", manage);
|
||||
if (!Context.EmailConfirmed)
|
||||
{
|
||||
_confirmEmailButton = HtmlAssert.HasElement("button#email-verification", manage);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<Email> SendConfirmationEmailAsync()
|
||||
{
|
||||
Assert.False(Context.EmailConfirmed);
|
||||
|
||||
var response = await Client.SendAsync(_changeEmailForm, _confirmEmailButton);
|
||||
var goToManage = ResponseAssert.IsRedirect(response);
|
||||
var manageResponse = await Client.GetAsync(goToManage);
|
||||
var manage = await ResponseAssert.IsHtmlDocumentAsync(manageResponse);
|
||||
|
||||
return new Email(Client, manage, Context);
|
||||
}
|
||||
|
||||
internal async Task<Email> SendUpdateEmailAsync(string newEmail)
|
||||
{
|
||||
var response = await Client.SendAsync(_changeEmailForm, _changeEmailButton, new Dictionary<string, string>
|
||||
{
|
||||
["Input_NewEmail"] = newEmail
|
||||
});
|
||||
var goToManage = ResponseAssert.IsRedirect(response);
|
||||
var manageResponse = await Client.GetAsync(goToManage);
|
||||
var manage = await ResponseAssert.IsHtmlDocumentAsync(manageResponse);
|
||||
|
||||
return new Email(Client, manage, Context);
|
||||
}
|
||||
|
||||
internal object GetEmail() => _emailInput.GetAttribute("value");
|
||||
|
||||
internal object GetNewEmail() => _newEmailInput.GetAttribute("value");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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;
|
||||
|
|
@ -13,15 +13,14 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
public class Index : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlAnchorElement _profileLink;
|
||||
private readonly IHtmlAnchorElement _emailLink;
|
||||
private readonly IHtmlAnchorElement _changePasswordLink;
|
||||
private readonly IHtmlAnchorElement _twoFactorLink;
|
||||
private readonly IHtmlAnchorElement _externalLoginLink;
|
||||
private readonly IHtmlAnchorElement _personalDataLink;
|
||||
private readonly IHtmlFormElement _updateProfileForm;
|
||||
private readonly IHtmlElement _emailInput;
|
||||
private readonly IHtmlElement _userNameInput;
|
||||
private readonly IHtmlElement _updateProfileButton;
|
||||
private readonly IHtmlElement _confirmEmailButton;
|
||||
public static readonly string Path = "/";
|
||||
|
||||
public Index(HttpClient client, IHtmlDocument manage, DefaultUIContext context)
|
||||
|
|
@ -30,6 +29,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
Assert.True(Context.UserAuthenticated);
|
||||
|
||||
_profileLink = HtmlAssert.HasLink("#profile", manage);
|
||||
_emailLink = HtmlAssert.HasLink("#email", manage);
|
||||
_changePasswordLink = HtmlAssert.HasLink("#change-password", manage);
|
||||
_twoFactorLink = HtmlAssert.HasLink("#two-factor", manage);
|
||||
if (Context.ContosoLoginEnabled)
|
||||
|
|
@ -38,13 +38,8 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
}
|
||||
_personalDataLink = HtmlAssert.HasLink("#personal-data", manage);
|
||||
_updateProfileForm = HtmlAssert.HasForm("#profile-form", manage);
|
||||
_emailInput = HtmlAssert.HasElement("#Input_Email", manage);
|
||||
_userNameInput = HtmlAssert.HasElement("#Username", manage);
|
||||
_updateProfileButton = HtmlAssert.HasElement("#update-profile-button", manage);
|
||||
if (!Context.EmailConfirmed)
|
||||
{
|
||||
_confirmEmailButton = HtmlAssert.HasElement("button#email-verification", manage);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<TwoFactorAuthentication> ClickTwoFactorLinkAsync(bool consent = true)
|
||||
|
|
@ -71,31 +66,6 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
return new TwoFactorAuthentication(Client, twoFactor, Context);
|
||||
}
|
||||
|
||||
internal async Task<Index> SendConfirmationEmailAsync()
|
||||
{
|
||||
Assert.False(Context.EmailConfirmed);
|
||||
|
||||
var response = await Client.SendAsync(_updateProfileForm, _confirmEmailButton);
|
||||
var goToManage = ResponseAssert.IsRedirect(response);
|
||||
var manageResponse = await Client.GetAsync(goToManage);
|
||||
var manage = await ResponseAssert.IsHtmlDocumentAsync(manageResponse);
|
||||
|
||||
return new Index(Client, manage, Context);
|
||||
}
|
||||
|
||||
internal async Task<Index> SendUpdateProfileAsync(string newEmail)
|
||||
{
|
||||
var response = await Client.SendAsync(_updateProfileForm, _updateProfileButton, new Dictionary<string, string>
|
||||
{
|
||||
["Input_Email"] = newEmail
|
||||
});
|
||||
var goToManage = ResponseAssert.IsRedirect(response);
|
||||
var manageResponse = await Client.GetAsync(goToManage);
|
||||
var manage = await ResponseAssert.IsHtmlDocumentAsync(manageResponse);
|
||||
|
||||
return new Index(Client, manage, Context);
|
||||
}
|
||||
|
||||
public async Task<ChangePassword> ClickChangePasswordLinkAsync()
|
||||
{
|
||||
var goToChangePassword = await Client.GetAsync(_changePasswordLink.Href);
|
||||
|
|
@ -103,8 +73,6 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
return new ChangePassword(Client, changePasswordDocument, Context);
|
||||
}
|
||||
|
||||
internal string GetEmail() => _emailInput.GetAttribute("value");
|
||||
|
||||
internal object GetUserName() => _userNameInput.GetAttribute("value");
|
||||
|
||||
public async Task<SetPassword> ClickChangePasswordLinkExternalLoginAsync()
|
||||
|
|
@ -123,6 +91,13 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
return new PersonalData(Client, personalData, Context);
|
||||
}
|
||||
|
||||
public async Task<Email> ClickEmailLinkAsync()
|
||||
{
|
||||
var goToEmail = await Client.GetAsync(_emailLink.Href);
|
||||
var email = await ResponseAssert.IsHtmlDocumentAsync(goToEmail);
|
||||
return new Email(Client, email, Context);
|
||||
}
|
||||
|
||||
public async Task<LinkExternalLogin> ClickLinkLoginAsync()
|
||||
{
|
||||
var goToExternalLogin = await Client.GetAsync(_externalLoginLink.Href);
|
||||
|
|
|
|||
|
|
@ -53,5 +53,22 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
|
||||
return new Index(Client, index, Context.WithAuthenticatedUser());
|
||||
}
|
||||
|
||||
public async Task<RegisterConfirmation> SubmitRegisterFormWithConfirmation(string userName, string password, bool hasRealEmail = false)
|
||||
{
|
||||
var registered = await Client.SendAsync(_registerForm, new Dictionary<string, string>()
|
||||
{
|
||||
["Input_Email"] = userName,
|
||||
["Input_Password"] = password,
|
||||
["Input_ConfirmPassword"] = password
|
||||
});
|
||||
|
||||
var registeredLocation = ResponseAssert.IsRedirect(registered);
|
||||
Assert.Equal(RegisterConfirmation.Path + "?email="+userName, registeredLocation.ToString());
|
||||
var registerResponse = await Client.GetAsync(registeredLocation);
|
||||
var register = await ResponseAssert.IsHtmlDocumentAsync(registerResponse);
|
||||
|
||||
return new RegisterConfirmation(Client, register, hasRealEmail ? Context.WithRealEmailSender() : Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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.Net.Http;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
// 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.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Microsoft.AspNetCore.Identity.FunctionalTests.Account;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||
{
|
||||
public class RegisterConfirmation : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlAnchorElement _confirmLink;
|
||||
public static readonly string Path = "/Identity/Account/RegisterConfirmation";
|
||||
|
||||
public RegisterConfirmation(
|
||||
HttpClient client,
|
||||
IHtmlDocument register,
|
||||
DefaultUIContext context)
|
||||
: base(client, register, context)
|
||||
{
|
||||
if (Context.HasRealEmailSender)
|
||||
{
|
||||
Assert.Empty(Document.QuerySelectorAll("#confirm-link"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_confirmLink = HtmlAssert.HasLink("#confirm-link", Document);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ConfirmEmail> ClickConfirmLinkAsync()
|
||||
{
|
||||
var goToConfirm = await Client.GetAsync(_confirmLink.Href);
|
||||
var confirm = await ResponseAssert.IsHtmlDocumentAsync(goToConfirm);
|
||||
|
||||
return await ConfirmEmail.Create(_confirmLink, Client, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
|
@ -37,6 +38,59 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanRegisterAUserWithRequiredConfirmation()
|
||||
{
|
||||
// Arrange
|
||||
void ConfigureTestServices(IServiceCollection services) { services.Configure<IdentityOptions>(o => o.SignIn.RequireConfirmedAccount = true); };
|
||||
|
||||
var server = ServerFactory
|
||||
.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices));
|
||||
var client = server.CreateClient();
|
||||
var client2 = server.CreateClient();
|
||||
|
||||
var userName = $"{Guid.NewGuid()}@example.com";
|
||||
var password = $"!Test.Password1$";
|
||||
|
||||
// Act & Assert
|
||||
var register = await UserStories.RegisterNewUserAsyncWithConfirmation(client, userName, password);
|
||||
|
||||
// Since we aren't confirmed yet, login should fail until we confirm
|
||||
await UserStories.LoginFailsWithWrongPasswordAsync(client, userName, password);
|
||||
await register.ClickConfirmLinkAsync();
|
||||
await UserStories.LoginExistingUserAsync(client, userName, password);
|
||||
}
|
||||
|
||||
private class FakeEmailSender : IEmailSender
|
||||
{
|
||||
public Task SendEmailAsync(string email, string subject, string htmlMessage)
|
||||
=> Task.CompletedTask;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RegisterWithRealConfirmationDoesNotShowLink()
|
||||
{
|
||||
// Arrange
|
||||
void ConfigureTestServices(IServiceCollection services) {
|
||||
services.Configure<IdentityOptions>(o => o.SignIn.RequireConfirmedAccount = true);
|
||||
services.AddSingleton<IEmailSender, FakeEmailSender>();
|
||||
};
|
||||
|
||||
var server = ServerFactory
|
||||
.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices));
|
||||
var client = server.CreateClient();
|
||||
var client2 = server.CreateClient();
|
||||
|
||||
var userName = $"{Guid.NewGuid()}@example.com";
|
||||
var password = $"!Test.Password1$";
|
||||
|
||||
// Act & Assert
|
||||
var register = await UserStories.RegisterNewUserAsyncWithConfirmation(client, userName, password, hasRealEmailSender: true);
|
||||
|
||||
// Since we aren't confirmed yet, login should fail until we confirm
|
||||
await UserStories.LoginFailsWithWrongPasswordAsync(client, userName, password);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanRegisterAUser_WithGlobalAuthorizeFilter()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,17 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
return await register.SubmitRegisterFormForValidUserAsync(userName, password);
|
||||
}
|
||||
|
||||
internal static async Task<RegisterConfirmation> RegisterNewUserAsyncWithConfirmation(HttpClient client, string userName = null, string password = null, bool hasRealEmailSender = false)
|
||||
{
|
||||
userName = userName ?? $"{Guid.NewGuid()}@example.com";
|
||||
password = password ?? $"!Test.Password1$";
|
||||
|
||||
var index = await Index.CreateAsync(client);
|
||||
var register = await index.ClickRegisterLinkAsync();
|
||||
|
||||
return await register.SubmitRegisterFormWithConfirmation(userName, password, hasRealEmailSender);
|
||||
}
|
||||
|
||||
|
||||
internal static async Task<Index> LoginExistingUserAsync(HttpClient client, string userName, string password)
|
||||
{
|
||||
|
|
@ -82,16 +93,18 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
return await externalLogin.SendEmailAsync(email);
|
||||
}
|
||||
|
||||
internal static async Task<Account.Manage.Index> SendEmailConfirmationLinkAsync(Index index)
|
||||
internal static async Task<Email> SendEmailConfirmationLinkAsync(Index index)
|
||||
{
|
||||
var manage = await index.ClickManageLinkAsync();
|
||||
return await manage.SendConfirmationEmailAsync();
|
||||
var email = await manage.ClickEmailLinkAsync();
|
||||
return await email.SendConfirmationEmailAsync();
|
||||
}
|
||||
|
||||
internal static async Task<Account.Manage.Index> SendUpdateProfileAsync(Index index, string newEmail)
|
||||
internal static async Task<Email> SendUpdateEmailAsync(Index index, string newEmail)
|
||||
{
|
||||
var manage = await index.ClickManageLinkAsync();
|
||||
return await manage.SendUpdateProfileAsync(newEmail);
|
||||
var email = await manage.ClickEmailLinkAsync();
|
||||
return await email.SendUpdateEmailAsync(newEmail);
|
||||
}
|
||||
|
||||
internal static async Task<Index> LoginWithSocialLoginAsync(HttpClient client, string userName)
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
|
||||
private class MySignInManager : SignInManager<PocoUser>
|
||||
{
|
||||
public MySignInManager(UserManager<PocoUser> manager, IHttpContextAccessor context, IUserClaimsPrincipalFactory<PocoUser> claimsFactory) : base(manager, context, claimsFactory, null, null, null) { }
|
||||
public MySignInManager(UserManager<PocoUser> manager, IHttpContextAccessor context, IUserClaimsPrincipalFactory<PocoUser> claimsFactory) : base(manager, context, claimsFactory, null, null, null, null) { }
|
||||
}
|
||||
|
||||
private class MyUserManager : UserManager<PocoUser>
|
||||
|
|
@ -357,4 +357,4 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var signInManager = new Mock<SignInManager<PocoUser>>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object, new DefaultUserConfirmation<PocoUser>());
|
||||
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(shouldStampValidate ? user : default).Verifiable();
|
||||
|
||||
if (shouldStampValidate)
|
||||
|
|
@ -164,7 +164,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var signInManager = new SignInManager<PocoUser>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object, new DefaultUserConfirmation<PocoUser>());
|
||||
userManager.Setup(u => u.GetUserAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(user).Verifiable();
|
||||
claimsManager.Setup(c => c.CreateAsync(user)).ReturnsAsync(new ClaimsPrincipal()).Verifiable();
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var signInManager = new Mock<SignInManager<PocoUser>>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object, new DefaultUserConfirmation<PocoUser>());
|
||||
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(default(PocoUser)).Verifiable();
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(options.Object);
|
||||
|
|
@ -241,7 +241,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var signInManager = new Mock<SignInManager<PocoUser>>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object, new DefaultUserConfirmation<PocoUser>());
|
||||
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsPrincipal>())).Throws(new Exception("Shouldn't be called"));
|
||||
signInManager.Setup(s => s.SignInAsync(user, false, null)).Throws(new Exception("Shouldn't be called"));
|
||||
var services = new ServiceCollection();
|
||||
|
|
@ -277,7 +277,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var signInManager = new Mock<SignInManager<PocoUser>>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object, new DefaultUserConfirmation<PocoUser>());
|
||||
signInManager.Setup(s => s.ValidateTwoFactorSecurityStampAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(shouldStampValidate ? user : default).Verifiable();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
|
|
@ -309,4 +309,4 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
public Task TwoFactorRememberClientOnValidatePrincipalRejectsWhenValidateSecurityStampFails()
|
||||
=> RunRememberClientCookieTest(shouldStampValidate: false, validationSuccess: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,13 +69,13 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
[Fact]
|
||||
public void ConstructorNullChecks()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>("userManager", () => new SignInManager<PocoUser>(null, null, null, null, null, null));
|
||||
Assert.Throws<ArgumentNullException>("userManager", () => new SignInManager<PocoUser>(null, null, null, null, null, null, null));
|
||||
var userManager = MockHelpers.MockUserManager<PocoUser>().Object;
|
||||
Assert.Throws<ArgumentNullException>("contextAccessor", () => new SignInManager<PocoUser>(userManager, null, null, null, null, null));
|
||||
Assert.Throws<ArgumentNullException>("contextAccessor", () => new SignInManager<PocoUser>(userManager, null, null, null, null, null, null));
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
var context = new Mock<HttpContext>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(context.Object);
|
||||
Assert.Throws<ArgumentNullException>("claimsFactory", () => new SignInManager<PocoUser>(userManager, contextAccessor.Object, null, null, null, null));
|
||||
Assert.Throws<ArgumentNullException>("claimsFactory", () => new SignInManager<PocoUser>(userManager, contextAccessor.Object, null, null, null, null, null));
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
|
|
@ -124,7 +124,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
options.Setup(a => a.Value).Returns(identityOptions);
|
||||
var claimsFactory = new UserClaimsPrincipalFactory<PocoUser, PocoRole>(manager.Object, roleManager.Object, options.Object);
|
||||
var logger = new TestLogger<SignInManager<PocoUser>>();
|
||||
var helper = new SignInManager<PocoUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
var helper = new SignInManager<PocoUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger, new Mock<IAuthenticationSchemeProvider>().Object, new DefaultUserConfirmation<PocoUser>());
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
|
||||
|
|
@ -154,7 +154,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
options.Setup(a => a.Value).Returns(identityOptions);
|
||||
var claimsFactory = new UserClaimsPrincipalFactory<PocoUser, PocoRole>(manager.Object, roleManager.Object, options.Object);
|
||||
var logger = new TestLogger<SignInManager<PocoUser>>();
|
||||
var helper = new SignInManager<PocoUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
var helper = new SignInManager<PocoUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger, new Mock<IAuthenticationSchemeProvider>().Object, new DefaultUserConfirmation<PocoUser>());
|
||||
|
||||
// Act
|
||||
var result = await helper.CheckPasswordSignInAsync(user, "bogus", false);
|
||||
|
|
@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
options.Setup(a => a.Value).Returns(identityOptions);
|
||||
var claimsFactory = new UserClaimsPrincipalFactory<PocoUser, PocoRole>(manager, roleManager.Object, options.Object);
|
||||
schemeProvider = schemeProvider ?? new Mock<IAuthenticationSchemeProvider>().Object;
|
||||
var sm = new SignInManager<PocoUser>(manager, contextAccessor.Object, claimsFactory, options.Object, null, schemeProvider);
|
||||
var sm = new SignInManager<PocoUser>(manager, contextAccessor.Object, claimsFactory, options.Object, null, schemeProvider, new DefaultUserConfirmation<PocoUser>());
|
||||
sm.Logger = logger ?? NullLogger<SignInManager<PocoUser>>.Instance;
|
||||
return sm;
|
||||
}
|
||||
|
|
@ -575,7 +575,7 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
var signInManager = new Mock<SignInManager<PocoUser>>(manager.Object,
|
||||
new HttpContextAccessor { HttpContext = context },
|
||||
new Mock<IUserClaimsPrincipalFactory<PocoUser>>().Object,
|
||||
null, null, new Mock<IAuthenticationSchemeProvider>().Object)
|
||||
null, null, new Mock<IAuthenticationSchemeProvider>().Object, null)
|
||||
{ CallBase = true };
|
||||
//signInManager.Setup(s => s.SignInAsync(user, It.Is<AuthenticationProperties>(p => p.IsPersistent == isPersistent),
|
||||
//externalLogin? loginProvider : null)).Returns(Task.FromResult(0)).Verifiable();
|
||||
|
|
|
|||
Loading…
Reference in New Issue