How to login with "UserName" instead of "Email" in MVC Identity? - asp.net

I need to set my login to use username instead of email address, how can I change it?

It's actually using the e-mail address as the username, so in the ASPNetUsers table, you'll see both the username and email fields with the email address.
Go into the AccountController, look for Register method (POST).
Change this:
var user = new ApplicationUser { UserName = model.Email, Email = model.Email};
to this:
var user = new ApplicationUser
{
UserName = model.UserName,
Email = model.Email
};
Then go into the Login.cshtml and change all corresponding e-mail model fields to username instead.
Finally, go into the Login method (POST) in the AccountController and change model.Email to model.UserName.
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password,
model.RememberMe, shouldLockout: false);
You also have to make changes in AccountViewModels.cs in order to introduce your new UserName property.

Here is how you do it
var user = await _userManager.Users
.FirstOrDefaultAsync(u => u.UserName == username || u.Email == username);
if (user != null){
var result = await _signInManager
.PasswordSignInAsync(/*email*/user.Email, password, false, false);
/*removed for brevity*/
}
Think you have a user having username=test and email=myemail#example.com then you would like to allow users to authenticate using test instead of myemail#... `
PS. While the answer from #Jason works, sometimes you'd like to authenticate a user with real username and password, not using the email.
In this case use my answer

Related

Bcrypt Verify always returning false

[HttpPost("signUp")]
public async Task<ActionResult<Users>> PostUserRegister(Users user)
{
if (userEmailExists(user.Email))
{
return BadRequest();
}
string salt = BC.GenerateSalt(12);
// hash password
user.Password = BC.HashPassword(user.Password, salt);
_context.Database.ExecuteSqlRaw("EXECUTE dbo.UserRegister #userName, #firstName, #lastName, #Password, #userEmail, #gender, #dob",
new SqlParameter("#userName", user.UserName.ToString()),
new SqlParameter("#firstName", user.FirstName.ToString()),
new SqlParameter("#lastName", user.LastName.ToString()),
new SqlParameter("#Password", user.Password.ToString()),
new SqlParameter("#userEmail", user.Email.ToString()),
new SqlParameter("#gender", user.Gender.ToString()),
new SqlParameter("#dob", user.Dob));
/* var format = "dd/MM/yyyy";
var date = DateTime.ParseExact(user.Dob, format);*/
return Ok(user);
//_context.Users.Add(users);
//await _context.SaveChangesAsync();
//return CreatedAtAction("GetUsers", new { id = users.UserId }, users);
}
Im siging a new user up like this. Hashing the password using Bcrypt.
using BC = BCrypt.Net.BCrypt;
[HttpPost("login")]
public async Task<ActionResult<Users>> PostUserLogin(Users user)
{
// get account from database
var account = _context.Users.SingleOrDefault(x => x.Email == user.Email);
// check account found and verify password
if (account == null || !BC.Verify(user.Password, account.Password))
{
// authentication failed
return Unauthorized(user);
}
else
{
// authentication successful
return Ok(user);
}
Then I try to verify the password in the login function. When i debug to see the values of user.Password and account.Password they are correct. the user.Password is equal to the password the user entered to register and the account.Password is the Hashed password stored in the database. I was trying to follow this tutorial ASP.NET Core 3.1 - Hash and Verify Passwords with BCrypt
I have read the blog you provided. And I think we should double check below points.
The format of Password in your db,if the orginal password is 11, then the value stored should like :
$2a$12$NTuJLk9/xZnlxP.oFj1mu.1ZypqYP4YuS1QbTBy7ofJwzKLSEEVBq
In this line BC.Verify(user.Password, account.Password),
The value of user.Password
user.Password == 11
And the value of account.Password
account.Password == $2a$12$NTuJLk9/xZnlxP.oFj1mu.1ZypqYP4YuS1QbTBy7ofJwzKLSEEVBq
Please double check it, if you still have some issue, you can add the picture with debugging result.
i have same problem with bCrypt like you.
The main problem was much simpler than I thought. The main reason for this was that I used uppercase and lowercase letters when I received and saved the password.
I Fixed this problem with make my password input to lower and save it to db
And When i want to verify it , i make the password lowercase again .
user.Password = BC.HashPassword(user.Password.ToLower(), salt);
and when you want to Verify , use it like this:
if (account == null || !BC.Verify(user.Password.ToLower(),account.Password))
I Think This is your question Answer.

Email confirmation token is not sent to user mail in asp.net project

I used this line of code to send a confirmation-mail-token to a registering user's mail:
var token = await userManager.GenerateEmailConfirmationTokenAsync(user);
but nothing is gotten in the user email.
I tried Gmail and Outlook accounts.
I tried "Less secure app access".
I logged the token to a file and it indeed logged in the file. This shows apparently, that the token is sent to the mail account, but not accepted by the account.
Here is a quotation from my code :
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel model)
{ // ModelState will give the error remarks onto the form if the model fields don't fit the criteries /not valid.
if (ModelState.IsValid)
{
// Copy data from RegisterViewModel to ApplicationUser
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
City = model.City
};
// Store user data in AspNetUsers database table
var result = await userManager.CreateAsync(user, model.Password);// in this signature of the method there is a password indeed
// If user is successfully created, sign-in the user using
// SignInManager and redirect to index action of HomeController
if (result.Succeeded)
{ // creating a token which will be sent within the confirmation link.
var token = await userManager.GenerateEmailConfirmationTokenAsync(user);
var confirmationLink = Url.Action("ConfirmEmail", "Account",
new { userId = user.Id, token = token }, Request.Scheme);
logger.Log(LogLevel.Warning, confirmationLink); // to c:\DemoLogs
I run it in debug mode , and checked the mail address in 'user.Email' which it is appeared correctly.

Creating users with no password using ASP.NET Identity

I have been given the requirement to provide the ability to create users through the UI with no password. I am trying to accomplish this using ASP.NET Identity.
I am able to successfully create a user without a password using the UserManager's Create method:
if (vm.ShouldHavePassword)
{
userManager.Create(userToInsert, vm.Password);
}
else
{
userManager.Create(userToInsert);
}
After the call to the Create method, the test user gets successfully saved into our AspNetUsers table. And when I do not provide a password, the PasswordHash column in our AspNetUsers table is set to NULL.
My issue is, I cannot login as the test user that does not have a password. The following is the method call that we use to validate a user's credentials:
result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
I attempted to login as a test user that has a NULL PasswordHash multiple times. To do this, I do not provide a password in our login form. As a result, a NULL password is passed into the PasswordSignInAsync method. The return value of this method call is always SignInStatus.Failure.
Using ASP.NET Identity, how can I configure my code to correctly authenticate user credentials when the credentials contain a NULL password, and the user in the database contains a NULL PasswordHash? Is such a thing even possible?
Yes you can. ASP.NET Identity Framework is fully customizable. Just override PasswordValidator.ValidateAsync and PasswordHasher.VerifyHashedPassword methods like this:
internal class CustomPasswordValidator: PasswordValidator
{
public override async Task<IdentityResult> ValidateAsync(string item)
{
if (string.IsNullOrEmpty(item)) return IdentityResult.Success;
return await base.ValidateAsync(item);
}
}
internal class CustomPasswordHasher : PasswordHasher
{
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
if (hashedPassword == null && string.IsNullOrEmpty(providedPassword))
return PasswordVerificationResult.Success;
return base.VerifyHashedPassword(hashedPassword, providedPassword);
}
}
And set them like this:
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
manager.PasswordValidator = new CustomPasswordValidator();
manager.PasswordHasher = new CustomPasswordHasher();
Okay, what you need to do is find the user (AspNetUsers user) using your db context. After you have the user, you can check if their PasswordHash is null.
If yes, then just sign them in using SignInManager.SignIn.
If not, use SignInManager.PasswordSignIn.
example..
//alternatively, you can find the user using Email, Id or some other unique field
var user = db.AspNetUsers.FirstOrDefault(p => p.UserName);
if (user != null)
{
if (user.PasswordHash == null)
await SignInManager.SignInAsync(user, true, true);
else
await SignInManager.PasswordSignInAsync(model.UserName, model.Password,
model.RememberMe, shouldLockout: false);
}
Hope it helps.
I don't think you can validate user without password. As a workaround: Instead of blank password, I'll recommend to use some Dummy/Common password from C# code, both while creating User and while validating credential
When creating user
if (vm.ShouldHavePassword)
{
userManager.Create(userToInsert, vm.Password);
}
else
{
userManager.Create(userToInsert, "someDummy123$");
}
When validating
result = await SignInManager.PasswordSignInAsync(model.UserName, "someDummy123$", model.RememberMe, shouldLockout: false);

Use Username instead of Email for identity in Asp.net mvc5

Whenever I create a new application with visual studio 2013 express for web and using the individual accounts authentication and i hit the register button I notice that it implements 'Email' instead of 'Username' and the same is in the LoginViewModel as it uses Email to Sign in instead of Username. How can i change this to use Username instead of the default Email without trouble? Also i would like to know how to convert the default 'guid' that is a string type to 'id' (integer type).
The linked question in the accepted answer descibes how to use Email instead of UserName, OP wanted the UserName instead of email which is what I was looking for in Identity 2.0 in an MVC project.
In case anyone else gets here from a google search it is actually very easy to do this. If you look at the register post action it is simply setting the UserName to the Email address. So.........
Add UserName to the RegisterViewModel and add it to the register view.
<div class="form-group">
#Html.LabelFor(m => m.UserName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control", #placeholder = "Username or email" })
</div>
</div>
In the Register Post Action on the AccountController set the UserName to the ViewModel's UserName and the Email to the ViewModel's Email.
var user = new ApplicationUser { UserName = model.UserName, Email = model.Email };
In order to make email as non unique:
Configure below in IdentityConfig
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};
Please look into this thread
Thread Details :
Assumptions:
Username is unique for each user. It is either input by user or generated by application on registration.
No # symbol allowed in Username.
Remove EmailAddress annotation and define Display text in the default LoginViewModel:
public class LoginViewModel
{
[Required]
[Display(Name = "Username/Email")]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
As user can enter either Username or Email, so we will make # character for validation criteria. Here is the flow to be implemented:
If in the string # is present, apply Email validation else apply Username format validation.
In case of valid Email, first we need to get Username. As it is considered that Username is unique so we can get it with userManager.FindByEmailAsync method.
Use Username for SignIn verification.
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (model.Email.IndexOf('#') > -1)
{
//Validate email format
string emailRegex = #"^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}" +
#"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
#".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
Regex re = new Regex(emailRegex);
if (!re.IsMatch(model.Email))
{
ModelState.AddModelError("Email", "Email is not valid");
}
}
else
{
//validate Username format
string emailRegex = #"^[a-zA-Z0-9]*$";
Regex re = new Regex(emailRegex);
if (!re.IsMatch(model.Email))
{
ModelState.AddModelError("Email", "Username is not valid");
}
}
if (ModelState.IsValid)
{
var userName = model.Email;
if (userName.IndexOf('#') > -1)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
else
{
userName = user.UserName;
}
}
var result = await _signInManager.PasswordSignInAsync(userName, model.Password, model.RememberMe, lockoutOnFailure: false);
No special need to change in View. Run the application and test login with Email or Username.
Note: Keep in mind this tutorial follows MVC .Net Identity default structure.
You can also use username and/or password like this
var user = await _userManager.Users
.FirstOrDefaultAsync(u => u.UserName == username || u.Email == username);
if (user != null){
var result = await _signInManager
.PasswordSignInAsync(user.Email, password, false, false);
}

ASP.NET MVC Authentication by Using FormsAuthenticationTicket (may be)

I am a PHP guy but am in the process of making a log-in page in ASP.NET MVC4. I am expecting to store the ID, Username and Roles of the user in session. So far what I am doing is as follows. If I am correct it saves the cookie with the username.
[HttpPost]
public ActionResult Login(Models.UserLoginModel user)
{
if (ModelState.IsValid)
{
Models.User u = new Models.User();
if (u.IsValid(user.Username, user.Password))
{
FormsAuthentication.SetAuthCookie(user.Username, user.RememberMe);
return RedirectToAction("Index", "Accounts");
}
else
{
ModelState.AddModelError("", "Login data is incorrect!");
}
}
return View(user);
}
My interest is to store more information and control validation time. I was advised and asked to use FormAuthenticationTicket class. I replaced FormsAuthentication.SetAuthCookie(user.Username, user.RememberMe); with
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket
(
1,
user.Username,
DateTime.Now,
DateTime.Now.AddMinutes(30),
false,
"Some User Data",
FormsAuthentication.FormsCookiePath
);
Response.Cookies.Add
(
new HttpCookie
(
FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(ticket)
)
);
It looks cool, I didn't test it though, has flexibility. But problem is how I could receive this information.
How can I get these information back and determine if the user is logged in and also other necessary information saved inside the FormsAuthenticationTicket.
Thanks in advance.
Like you would any ticket:
var cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
var ticketInfo = FormsAuthentication.Decrypt(cookie.Value);
Since it's a security ticket, if you don't need to access the information from client JavaScript, also set HttpOnly to true. This means the cookie is only accessible on the server.

Resources