Unable to create user after deleting database - c#

I've been learning MVC and got to this part:
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.UserName, Email = model.Email };
UserManager.Delete(user);
//myDBLoginDetails ent = new myDBLoginDetails();
//ent.uspInsertUser(user.UserName, model.Password, model.FirstName, model.LastName, user.Email);
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
I thought everything was going smoothly and I successfully registered\saved users to the SQL Server db (no MDF file). To continue testing and such I remmed out the code to register\insert the users and deleted the table and recreated it so I could eventually start from scratch.
But then when I tried to re-register a user so I could step through the code to learn what all is going on I discovered my user(s) are still on my PC as I got the messages:
Name tempUser is already taken.
Email 'tempUser#email.com' is already taken.
I tried to delete the user (using UserManager.Delete(user);) but got the message:
[InvalidOperationException: The object cannot be deleted because it
was not found in the ObjectStateManager.]
I searched for an explanation and resolution but have failed, and only discovered there may be other\better ways to register\edit\delete users and frustration eventually set in.
So, I guess I need a couple things solved. I have a LoginDetalsEDmodel.edmx so am I still correct to use a Stored Proc or do I use the Framework? If the Framework then how do I do that?
And.... how do I get rid of the user(s) that are still on my computer (which are gone from the DB)?
I hope I explained this well enough as I'm still learning......

Related

localhost cannot connect to db while deployed code can

I am using Arvixe as my web host and have created a .NET 4.5 MVC app with individual user accounts. I created an ADO.NET Entity Data Model database first named "SecurityModel", updated my ApplicationDbContext to "joerdie_securityEntities", and switched my connection string to the following:
<add name="joerdie_securityEntities" connectionString="Data Source=localhost;Initial Catalog=joerdie_security;Integrated Security=false;User ID=myID;Password=myPassword" providerName="System.Data.SqlClient" />
I did this so that I could use my own SQL server db also hosted with Arvixe. When I deploy this base application, I am able to create a new user without an issue, and new users are entered into the SQL server database. However, when I try to create a new user in localhost the user creation fails in the following method during the declaration of "result".
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
try
{
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
catch (Exception e) {
Console.WriteLine(e.Message);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
An Exception is caught but is null, and I never make it to the following if statement. I am able to bring in other models to this exact SQL Server instance and they update just fine. How do I set this up to be able to debug on my localhost pointing to my SQL Server instance?
Edit: Adding Console output.
Exception thrown: 'System.Data.SqlClient.SqlException' in mscorlib.dll
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Request","time":"2018-03-24T02:31:06.2230673Z","tags":{"ai.operation.name":"POST Account/Register","ai.operation.id":"MJK7rNb0X7k=","ai.location.ip":"::1","ai.cloud.roleInstance":"joerdie-Desktop","ai.internal.sdkVersion":"web:2.2.0-738"},"data":{"baseType":"RequestData","baseData":{"ver":2,"id":"MJK7rNb0X7k=","name":"POST Account/Register","duration":"00:01:01.1920000","success":true,"responseCode":"200","url":"http://localhost:53015/Account/Register","properties":{"DeveloperMode":"true"}}}}
The thread 0x10ec has exited with code 0 (0x0).

Why sign in following Change Password in ASP.Net Core 2 MVC

The default project template in Visual Studio 2017 contains a function in the ManageController for the logged in User to change their password.
Following a successfull password change the user is then automatically signed in again
await _signInManager.SignInAsync(user, isPersistent: false);
What is the purpose of this sign in?
The full action method is below:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var changePasswordResult = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
if (!changePasswordResult.Succeeded)
{
AddErrors(changePasswordResult);
return View(model);
}
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation("User changed their password successfully.");
StatusMessage = "Your password has been changed.";
return RedirectToAction(nameof(ChangePassword));
}
Inside of ChangePasswordAsync, there is a call to UpdatePasswordHash, which itself makes a call to UpdateSecurityStampInternal. The implementation of UpdateSecurityStampInternal is not important - what is important is that this (obviously) updates the SecurityStamp property of the user.
Looking into how SignInManager works, you'll see that SignInAsync ends up with a call to UserClaimsPrincipalFactory's CreateAsync method, which itself calls into GenerateClaimsAsync. Inside of this implementation, you'll see the following:
if (UserManager.SupportsUserSecurityStamp)
{
id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType,
await UserManager.GetSecurityStampAsync(user)));
}
This means that after changing a password, the existing SecurityStampClaimType value will have changed. Reissuing a sign-in action ensures that a new ClaimsIdentity is created, which includes the new value of SecurityStamp.
This may not be the only reason for this sign-in action, but it does appear to be a reason.

How can I check if a password reset token is expired?

I'm using ASP.NET Identity, and I have the basic Forgot Password/Reset Password functionality in place.
When you fill out the form that you forgot your password, it creates a reset token using _userManager.GeneratePasswordResetTokenAsync(user)
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByNameAsync(model.Email);
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
{
return View("ForgotPasswordConfirmation");
}
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
$"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
return View("ForgotPasswordConfirmation");
}
// If we got this far, something failed, redisplay form
return View(model);
}
I noticed that the only validation the Reset Password page has is to check if the code is null, rather than also checking to see if it's still valid or not expired.
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPassword(string code = null)
{
if (code == null)
{
throw new Exception("A code must be supplied for password reset.");
}
var model = new ResetPasswordViewModel { Code = code };
return View(model);
}
It doesn't actually check to see if the token is valid until you attempt to reset your password and it calls _userManager.ResetPasswordAsync(user, model.Code, model.Password)
I'd like to be able to validate that the code is still valid when they hit the Reset Password page to display a message to the user, and not after they attempt to reset their password.
Is there a way to check if it's valid?
Following code works to verify if the reset token is valid:
1. Create code and send it to user
var code = await this._userManager.GeneratePasswordResetTokenAsync(user);
2. Verify token
[HttpGet]
public async Task<IActionResult> ResetPassword(string UserId, string token)
{
...
ApplicationUser user = //get user;
if(!await this._userManager.VerifyUserTokenAsync(user,this._userManager.Options.Tokens.PasswordResetTokenProvider, "ResetPassword", token)){
ViewBag.Message = this._localizer["tokenNotValid"].Value;
}
...
}
See UserManager code: https://github.com/aspnet/Identity/blob/rel/2.0.0/src/Microsoft.Extensions.Identity.Core/UserManager.cs#L29
If you check the UserManager.ResetPasswordAsync(...) method, tracing throug to the VerifyUserTokenAsync method, which simply does:
// Make sure the token is valid
var result = await _tokenProviders[tokenProvider].ValidateAsync(purpose, token, this, user);
You can just do this yourself as well, knowing that:
You can ask the DI Framework (e.g. via your controller constructor) for the token provider for your situation;
The purpose is just the hardcoded "ResetPassword" string;
The token is the code the user is using;
The user you should be able to get depending on how your view, e-mail, url, and whatever is set up (the default examples don't cover this I think, but you can easily put the user.Id in the "forgot password url" before the token itself, and extract it when you need it).
Then you can just call ValidateAsync yourself and adjust the view accordingly.

MVC 5 ASP.NET Identity - CreateAsync invalid user id

I have two websites using one database, I use asp.net identity (2.2.1.40403) and I have a problem I can't understand. Now, this is a third time this happened and I have no idea where the problem can be.
I have a register and send email method like this
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new User { UserName = model.Email, Email = model.Email, RegisterDate = DateTime.Now };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
//await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
await SendConfirmationEmail(user);
return View("ConfirmationEmailSent");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
private async Task SendConfirmationEmail(Dal.Models.User user)
{
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Potvrzení Vašeho účtu", "Prosím potvrďte svou emailovou adresu kliknutím zde.");
}
What happened is that when user registered he received URL when userId was set to 3d847c51-7217-49fe-ae9d-d8e46e291559, but in database the user was created with 95789d6e-b66e-4c9e-8ee4-fe384b82e838. I don't understand how this can happen. By the way there is no user in database with Id 3d847c51-7217-49fe-ae9d-d8e46e291559. Do you have any idea why and how this can happen?
I would suggest calling back the user by an identifier after create was successful to make sure the properties match up.
//...other code removed for brevity
var user = new User { UserName = model.Email, Email = model.Email, RegisterDate = DateTime.Now };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
//pick one
//user = await UserManager.FindById(user.Id);
//user = await UserManager.FindByName(user.UserName);
user = await UserManager.FindByEmailAsync(user.Email);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
await SendConfirmationEmail(user);
return View("ConfirmationEmailSent");
}
AddErrors(result);
//...other code removed for brevity
I am also suspect that issue is related to UserManager.CreateAsync() method. You are using correctly. I will rather use manually generated user id instead generated by UserManager.
In your case will be:
var user = new User { UserName = model.Email, Email = model.Email, RegisterDate = DateTime.Now };
user.Id = Guid.NewGuid().ToString();
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SendConfirmationEmail(user);
return View("ConfirmationEmailSent");
}

ASP.Net MVC - Two Step Authentication

Good Morning
In MVC there is a method in the manage controller being used. to generate a token.
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number);
Does anyone know where this generated token is saved. In the basic MVC example they use it to add a phone number and needs to be verified with the token being sms`d to the cellphone number supplied, this code is used to generate that token. But no where is that token being saved, there is no column in the db and is not being passed to the view in a hidden field. But the strange part is when you enter the code and submit it, it will do a comparison in the post method using the following
public async Task<ActionResult> VerifyPhoneNumber(string phoneNumber)
{
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), phoneNumber);
// Send an SMS through the SMS provider to verify the phone number
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
}
I cannot figure out where the GenerateChangePhoneNumberTokenAsync method will find the generated token to compare with the token being passed in with the model. Do anyone of you have an idea of where this could be found.
Kind Regards
The code is not stored in the database. The code generation and verification are handled internally by ASP.NET Identity. There's a corresponding action method in the "ManageController" that handles the phone number and code verification. Here is the code
public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
await SignInAsync(user, isPersistent: false);
}
return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess });
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "Failed to verify phone");
return View(model);
}
Notice the line that does the verification using the UserId, PhoneNumber and Code.
var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
Cheers.

Categories