Why ChangePhoneNumber always returns wrong code? - c#

I'm trying to restore password using UserManager and GenerateChangePhoneNumberTokenAsync method.
After trying to confirm that token by ChangePhoneNumberAsync but each time I receive the error about wrong code.
I tried different conditions and each time receiving the same error.
Generating token
var token = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.Username);
Confirming token
var verified = await _userManager.ChangePhoneNumberAsync(user, model.Phone, model.Token);
Startup.cs
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
config.SignIn.RequireConfirmedPhoneNumber = true;
config.Tokens.ChangePhoneNumberTokenProvider = "Phone";
})
Phone and username are the same.
var user = new ApplicationUser
{
Email = $"{_templateCustomerEmail}{(_context.Users.Count() + 1)}#{_appSettings.Domain}",
DateSignUp = DateTime.UtcNow,
FullName = model.FullName,
Id = Guid.NewGuid().ToString(),
PhoneNumber = model.Username,
EmailConfirmed = true,
PhoneNumberConfirmed = false,
UserName = model.Username
};
I expected really easy set up of these stuff. Unfortunately faced with kind a dummy issue.
Maybe issue is in method names or something else.

You have to call SetPhoneNumberAsync method before GenerateChangePhoneNumberTokenAsync. this is very important point.
I don't know how is your code.
this works.
await _userManager.SetPhoneNumberAsync(user, $"{model.CountryCode}{model.PhoneNumber}");
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber);
this does not work.
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber);
await _userManager.SetPhoneNumberAsync(user, $"{model.CountryCode}{model.PhoneNumber}");
Because it is using SecurityStamp for validation so every update query changes it.

https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.generatechangephonenumbertokenasync?view=aspnetcore-2.2
GenerateChangePhoneNumberTokenAsync takes a user and the phone number. You're giving it user and username, so when you try to change it (confirm the token), you're trying to match a phone number to a username which doesn't match so it gives an error.

Related

Why password checking always fail in ASP .NET Core Identity framework?

I'm making a web application with ASP .NET Core 3.1. I'm using Identity to build user login function.
I'm getting a problem in which registered user can't login, due to password checking always fail. I went ahead and create an user programmatically, then check password right after the creation, and the check still fail.
Did I forget to set something up?
More details:
I want user with roles so I set up custom Identity service like this. I think I forgot to set up some extra thing here.
// In Startup class
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddIdentity<IdentityUser, IdentityRole>((_options) =>
{
// Custom IdentityOptions configuration;
})
.AddDefaultUI()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
// ...
}
I tried create user programmatically and check the password right after that. The check still fail.
// In Startup.Configure() method
string username = "admin";
string password = "123456";
IdentityUser user = new IdentityUser(username);
await userManager.CreateAsync(user, password);
bool isCorrect = await userManager.CheckPasswordAsync(user, password);
// isCorrect is always false;
(I do make sure that the user is created successfully, and password is added successfully. I did view the database data and see the user there.)
I did check similar questions on StackOverflow, but their problem seems to be different from mine so it didn't help.
UserManager.CreateAsync method returns an IdentityResult that will tell you if user creation succeeded or not.
string username = "admin";
string password = "123456";
IdentityUser user = new IdentityUser(username);
IdentityResult result = await userManager.CreateAsync(user, password);
if (result.Succeded)
{
var actualUser = await userManager.FindByNameAsync(username);
if (actualUser != null)
{
bool isCorrect = await userManager.CheckPasswordAsync(actualUser, password);
}
}
else
{
// check what went wrong
var errors = result.Errors;
}
User creation is probably failing because password is weak.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.createasync?view=aspnetcore-6.0

ASP CORE Identity browser login fail but via UserManager.CheckPasswordAsync with literal string work

I'm use mvc core 3.1 with Identity 3.1.2, with default built-in UI:
services.AddIdentity<IdentityUser, IdentityRole>(opt =>
{
opt.User.RequireUniqueEmail = true;
opt.SignIn.RequireConfirmedEmail = false;
opt.SignIn.RequireConfirmedAccount = false;
}).AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
I wrote hard code that creates initial administrator user:
var userAdminExists = await _userManager.FindByNameAsync("Admin");
if (userAdminExists == null)
{
var user = new IdentityUser
{
Id = Guid.NewGuid().ToString(),
UserName = "Admin",
Email = "xxxxxx#gmail.com",
EmailConfirmed = true
};
var x = await _userManager.CreateAsync(user, _IConfiguration.GetValue<string>("defaultAdminPassword"));
await _userManager.AddToRoleAsync(user, "AdminRole");
}
(Of course I also tried to write the literal password inside the code, for those wondering about the IConfiguration, and I also watched the entries at break-points and everything worked as planned).
the user is created, but when i login with this email address and password in the browser i get "Invalid login attempt." (in normal response, status 200).
I wrote test code:
var pass = _configuration.GetValue<string>("defaultAdminPassword");
var res = await _userManager.CheckPasswordAsync(await _userManager.FindByEmailAsync("xxxx#gmail.com"), pass);
And of course it return true...
furthermore, also if i reset password via email reset link ("Forgot your password?") and i set new password, is not work...
but new users created through the "Register" UI interface, work great.
What am I missing?
When you use the Identity UI to sign in, you end up calling SignInManager.PasswordSignInAsync:
public virtual Task<SignInResult> PasswordSignInAsync(
string userName, string password, bool isPersistent, bool lockoutOnFailure);
As you can see from this signature, the first parameter is userName. When you use the UI as you've described, you provide the email address where the userName is expected. However, when you call FindByEmailAsync and pass the result into CheckPasswordAsync, you find the user based on Email and not UserName, which works.
When you register a new user using the Identity UI, you end up running this code:
await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
As you can see, this sets both the UserName and the Email to Input.Email. This is why you are able to sign in with these accounts.
when i login with this email address and password in the browser i get "Invalid login attempt." (in normal response, status 200).
If RequireConfirmedAccount option is set to true while configuring Identity service as below, the registered user login with that account but not confirming the account, which would cause this issue.
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
"Invalid login attempt" message
So please make sure the user confirm the account before user login app with that account. Besides, if account confirmation is not needed in your app, you can set RequireConfirmedAccount option is set to false.
options => options.SignIn.RequireConfirmedAccount = false

_UserManager.CreateAsync() returns sucess but does not save the user on database

I am building a web app in .Net Core 3.0 and everything is running smooth but I found a small issue:
I have a method to create a user in a controller that runs well, saves the user and its all ok.
But I have the need to have another method in another controler that can also create users, and this method is copy / paste from the other working method that works, uses the same UserManager that is IOC'ed, it returns sucess, but at the end the user is not in the database.
This has to be in another method as this one if for creating users for other people, where the password is auto generated. The password passes and does not give any error on the createAsync() and it complies with the settings in the startup.cs file
I have changed the method, tryed to stimulate the EF context, to check if it was something on it, but no....
[HttpPut]
[Authorize(Roles = "Admin")]
[Route("CreateEmployee")]
public async Task<IActionResult> CreateEmployee([FromQuery]string email)
{
var user = new IdentityUser { UserName = email, Email = email };
var pw = UserHelper.GenerateRandomPassword(10);
var userResult = await _UserManager.CreateAsync(user, pw);
var resultRole = await _UserManager.AddToRoleAsync(user, "Employee");
var code = await _UserManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = code },
protocol: Request.Scheme);
EmailSender sender = new EmailSender();
await sender.SendWelcomeEmailAsync("Email Header",
new NewUserData { ConfirmUrl = callbackUrl, Password = pw, Email = email, Username = $"" });
}
Inspecting the object userResult :
userResult .succeded = true
uuserResult er.Errors.Count = 0
Inspecting the object resultRole :
resultRole.succeded = true
resultRole.Errors.Count = 0

Asp.NET Identity Roles not working when attempting to add Role to User

I am currently adding Roles to our Database using the RoleManager with the CreateAsync(newRoleName) Method - which works correctly. But when I try to query that Role, it always returns that it doesn't exist (even though I can see it in the database).
Can anyone provide some insight on why I am not able to use the Role?
var roleExists = roleManager.RoleExistsAsync(role);
if (!roleExists.Result)
{
var newRole = new IdentityRole(role)
{
Name = role,
NormalizedName = role.ToUpper(),
};
var roleCreated = roleManager.CreateAsync(newRole);
Thread.Sleep(500); // Used to get result back first.
var roleExistsYet = roleManager.RoleExistsAsync(role);
if (!roleExists.Result)
{
// ALWAYS Returns [False]
}
}
The initial problem came about when we were creating a new User with the UserManager, and the following method would result in an error
var roleAddResult = userManager.AddToRoleAsync(newUser, "TestRole123");
Exception Error: Role [TESTROLE123] does not exist.
Note: I can see the entry for the Role 'TestRole123' (or any other role) in the Database in the table dbo.AspNetRoles.
Any insight or help is appreciated.
Environment: Visual Studio 2017, Asp.NET Core, C#
One of the issues I see - you need to use keyword await in front of *Async() methods:
var roleExists = await roleManager.RoleExistsAsync(role);
and
var roleCreated = await roleManager.CreateAsync(newRole);
etc. This will remove your need to do Thread.Sleep(500); - most likely the problem is with this line.
If you can't do async methods, use non-async versions of the methods:
var roleCreated = roleManager.Create(newRole);
I don't know how you declared your rolemanager, but following code works for me. It's configured in startup.cs and automatically creates a superuser if the roles haven't been created. Perhaps this can help you?
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
if (!roleManager.RoleExists("SuperUser"))
{
roleManager.Create(new IdentityRole("SuperUser"));
//superuser
var user = new ApplicationUser
{
UserName = " Name",
Email = "Email",
Firstname = "Firstname",
Lastname = "Lastname"
};
var pass = "AwesomePasswordOverHere";
var chkUser = await userManager.CreateAsync(user, pass);
//make superuser
if (chkUser.Succeeded)
{
await userManager.AddToRoleAsync(user.Id, "SuperUser");
}
}

Identity 2.0 Invalid Login Attempt

For some reason I am yet to discover, but after a successful registration and activation, I cannot login with the email address, instead I get an error "Invalid login attempt".
As ASP.NET Identity 2.0 has improved with the use of Email login, I have modified the registration form to actually store a true username as the existing registration just seemed to duplicate by storing Username with the email address.
Please see below the standard code that comes with Install-Package Microsoft.AspNet.Identity.Samples -Pre' following the creation of an empty ASP.NET Web Application (MVC) project:
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
My function is now as follows:
var user = new ApplicationUser { TitleId = model.TitleId, SexId = model.SexId, Forename = model.Forename, Surname = model.Surname, UserName = model.UserName, Email = model.Email, JoinDate = System.DateTime.Now };
As you can see UserName is now receiving a value from a form. This is all well and good except now I can't logon after registration and activation. The only work round is to modify the record by putting the value from the Email field into the UserName field which just seems daft.
Can somebody please advise as to what I might have missed?
You have to modify SignInHelper.PasswordSignIn method. By default it uses FindByNameAsync to check if user with given name exists:
public async Task<SignInStatus> PasswordSignIn(string userName, string password, bool isPersistent, bool shouldLockout)
{
var user = await UserManager.FindByNameAsync(userName);
// (...)
change it to use FindByEmailAsync:
var user = await UserManager.FindByEmailAsync(userName);
You can find SignInHelper class in *AppCode\IdentityConfig.cs` file.
In class AccountController.cs, method: public async Task<ActionResult> Login(LoginViewModel model, string returnUrl).
Modified this:
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
To this:
try
{
var user = db.Users.Where(u => u.Email.Equals(model.Email)).Single(); // where db is ApplicationDbContext instance
var result = await SignInManager.PasswordSignInAsync(user.UserName, model.Password, model.RememberMe, shouldLockout: false);
}
catch (InvalidOperationException)
{
// the user is not exist
}
The reason is UserName and UserEmail have different values but method PasswordSignInAsync only uses UserName to check for log in.
I had the same issue but found the solution to be a combination of both the accepted answer by Marcin and the answer by Hai. In AccountController.cs you need to use FindByEmailAsync(), instead of FindByNameAsync(), then use SignInManager.PasswordSignInAsync() but use the value of user.UserName as the first argument (as long as user is not null), instead of model.Email. So a complete answer, based on the current boiler plate code, would be something like this:
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
// (...) ModelState.IsValid, etc
string user_name = ""; // in case 'user' is null (user not found)
var user = await UserManager.FindByEmailAsync(model.Email);
if (user != null)
{
user_name = user.UserName;
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
// (...) Require the user to have a confirmed email before they can log on, etc
}
}
// don't use model.Email below, use the value from user.UserName (if user not null)
var result = await SignInManager.PasswordSignInAsync(user_name, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
// (...)
You can try change to bool value in Startup.cs file in your project. "true->false"
In this line, services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false)
Try To Edit The "RequireConfirmedAccount" Option from "true" to "false", it worked with me, in the program class.
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddEntityFrameworkStores<ApplicationDbContext>();
If you are using default authentication code generate , in Startup file you may see below code :
services.AddDefaultIdentity<addition>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
the code forces you to use email confirm and if you didn't do that earlier you get "Invalid login attempt" error

Categories