With asp.net core, all the login pages and viewmodels etc are hidden in referenced packages, so can't be directly changed. How do I allow login to still make use of usernames and not force the use of emails?
4 Answers
The first step is to scaffold identity to your application :
Scaffold Identity in ASP.NET Core projects
Then you could customize the Register.cshtml/Register.cshtml.cs and Login.cshtml/Login.cshtml.cs , update model and view , and change the logic in OnPostAsync function to fit your requirement .
To your requirement , you can follow the steps :
- Scaffold identity into your project .
Modify the
Register.cshtml.cs, add Username toInputModel:[Required] [DataType(DataType.Text)] [Display(Name = "User Name")] public string UserName { get; set; }Modify the
OnPostAsyncmethod :var user = new IdentityUser { UserName = Input.UserName, Email = Input.Email };Update the
Register.cshtmlto include the UserName :<div class="form-group"> <label asp-for="Input.UserName"></label> <input asp-for="Input.UserName" class="form-control"/> <span asp-validation-for="Input.UserName" class="text-danger"></span> </div>Modify the
Login.cshtml.cs, modifyInputModelto replace Email with UserName :[Required] [DataType(DataType.Text)] [Display(Name = "User Name")] public string UserName { get; set; }Modify the
Login.cshtml:<div class="form-group"> <label asp-for="Input.UserName"></label> <input asp-for="Input.UserName" class="form-control" /> <span asp-validation-for="Input.UserName" class="text-danger"></span> </div>Modify the
Login.cshtml.csOnPostAsyncmethod to use Username instead of email :var result = await _signInManager.PasswordSignInAsync(Input.UserName, Input.Password, Input.RememberMe, lockoutOnFailure: true);
By default ASP.NET Identity uses FindByNameAsync to check if user with given name exists , so that you don't need to override PasswordSignInAsync function in SignInManager . If you want to login with email , your could click here to update that .
2 Comments
OnPostAsync in Register.cshmtl.cs has to be updated too. Also, make sure to remove the email from the InputModel otherwise the validation will fail on server side (due to the [Required] attribute).Please consider that: When using the accepted answer, if you don't want your users to click stupid "Confirm email" button, you need to:
- Change
AddDefaultIdentityfunction in yourProgram.cstooptions.SignIn.RequireConfirmedAccount = false(not defaulttrue). - Delete everything that is assosiated with email confirmation in
Register.cshtml.cs
There is full, clear & working Register.cshtml.cs without any stupid email things.
#nullable disable
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;
namespace PhotoSite.Areas.Identity.Pages.Account
{
public class RegisterModel : PageModel
{
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
private readonly IUserStore<IdentityUser> _userStore;
private readonly ILogger<RegisterModel> _logger;
public RegisterModel(
UserManager<IdentityUser> userManager,
IUserStore<IdentityUser> userStore,
SignInManager<IdentityUser> signInManager,
ILogger<RegisterModel> logger)
{
_userManager = userManager;
_userStore = userStore;
_signInManager = signInManager;
_logger = logger;
}
[BindProperty]
public InputModel Input { get; set; }
public string ReturnUrl { get; set; }
public IList<AuthenticationScheme> ExternalLogins { get; set; }
public class InputModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "User Name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
public async Task OnGetAsync(string returnUrl = null)
{
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = CreateUser();
await _userStore.SetUserNameAsync(user, Input.UserName, CancellationToken.None);
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
private IdentityUser CreateUser()
{
try
{
return Activator.CreateInstance<IdentityUser>();
}
catch
{
throw new InvalidOperationException($"Can't create an instance of '{nameof(IdentityUser)}'. " +
$"Ensure that '{nameof(IdentityUser)}' is not an abstract class and has a parameterless constructor, or alternatively " +
$"override the register page in /Areas/Identity/Pages/Account/Register.cshtml");
}
}
}
}
Comments
Look inside Pages -> Login.cshtml page (Here, you will get a class named Login.cshtml.cs). Inside that class, you will get a method named 'OnPostAsync'
Change frontend as likes
And inside your 'Login.cshtml.cs' class change this method with your target Dashboard/Index url..
public async Task<IActionResult> OnPostAsync()
{
if (ModelState.IsValid)
{
var validated = _ADService.Validate(new NetworkCredential(LoginData.UserId, LoginData.Password));
if (validated)
{
if (await _identityService.SignInAsync(HttpContext, LoginData.UserId))
{
// return Redirect("Index");
return Redirect("../app/bootstrap.html");
}
ModelState.AddModelError("", "account does not exist in system!");
return Page();
}
ModelState.AddModelError("", "userid or password is invalid!");
return Page();
}
else
{
ModelState.AddModelError("", "userid or password is blank!");
return Page();
}
}
