Invalid token in reset password of Asp.Net web api - asp.net-mvc-4

I'm working on a project using Asp.NET web api, and my authentication system is based on identity 2.0. When user sends the ResetPassword form, he gets "Invalid token"
this is my forgotpassword method
public async Task<HttpResponseMessage> ForgotPassword(ForgotPasswordViewModel model)
{
if (!ModelState.IsValid)
{
HttpError error = new HttpError(ModelState, false);
error.Message = Resource.No_Item_Found_Message;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
HttpError error = new HttpError();
error.Message = Resource.Process_Failed;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
var provider = new DpapiDataProtectionProvider("ECommerceWebApp");
UserManager.UserTokenProvider = new DataProtectorTokenProvider<ECommerceUser, string>(provider.Create("UserToken"));
var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
code = HttpUtility.UrlEncode(code);
try
{
// var callbackUrl = new Uri(Url.Link("ResetPasswordRoute", new { userId = user.Id, code = code, newPassword = model.Password }));
var callbackUrl = Url.Link("Default", new { Controller = "Account", action = "ResetPassword", userId = user.Id, code = code });
await UserManager.SendEmailAsync(user.Id, "تغییر رمز عبور در IRI1", "<div style='font-family:tahoma;direction:rtl;text-align:right;font-size:12px;'>" + "<h3>اولین و بزرگترین مرکز دادوستد بدون واسطه در ایران و کشورهای همسایه</h3>لطفاً با کلیک بر روی گزینۀ تغییر رمز به صفحۀ مربوطه بروید : <br/><br/>تغییر رمز عبور <br/><br/><br/><a href='iri1.com'>Iri1 Web Sites</a>" + "</div>");
}
catch (Exception ex)
{
HttpError error = new HttpError();
error.Message = ex.Message;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
return Request.CreateResponse(Resource.Reset_Password_Message_Client);
}
and this is my ResetPassword method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return RedirectToAction("ResetPasswordConfirmation", "Account");
}
var code = HttpUtility.UrlDecode(model.Code);
var result = await UserManager.ResetPasswordAsync(user.Id, code, model.Password);
if (result.Succeeded)
{
return RedirectToAction("ResetPasswordConfirmation", "Account");
}
AddErrors(result);
return View();
}
I still get invalid token error

I've just begun learning Identity Authentication and have no way to run samples from the Internet(I've got no visual studio). But I've noticed this method from GidHub samples, which seems to me to be wrong:
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPassword(string code = null)
{
return code == null ? View("Error") : View();
}
In my humble opinion this method should do this:
return code == null ? View("Error") : View(new ResetPasswordViewModel{Code = code});
And thus the hidden field in ResetPassword view contains the Code. When the user clicks the submit button this code will be posted with the email and password to the httppost ResetPassword action where you can access the code thus: model.Code
Now I hope you've got a valid token

Related

Net Maui android app shows blank page after login (Azure B2C) the next time after a successful login and logout

I am doing a login flow in .net maui, first time I try the flow works properly showing the landing page, after a successful logout, I try login again and one blank page is shown instead of the landing page.
I am using shell and the login code is the following
public partial class LoginPageViewModel : BaseViewModel
{
private readonly IAuthNService _authNService;
public LoginPageViewModel(IAuthNService authNService)
{
_authNService = authNService;
}
[ICommand]
async void Login()
{
try
{
var result = await _authNService.LoginAsync(CancellationToken.None);
var token = result?.IdToken;
if (token != null)
{
var handler = new JwtSecurityTokenHandler();
var data = handler.ReadJwtToken(token);
var claims = data.Claims.ToList();
if (data != null)
{
await Shell.Current.GoToAsync($"//{nameof(DashboardPage)}", true);
}
}
}
catch (MsalClientException ex)
{
await Toast.Make(ex.Message).Show();
}
catch (Exception ex)
{
await Toast.Make(ex.Message).Show();
}
}
}

how to delete identity users on delete cascade?

I am building an application using ASP.NET CORE 3.1 and built identity using built in funcations. When I delete or update I want to delete users and related entities from aspnetuserroles and aspnetusers.
I made an update users but seems verbose and I cannot make it work yet with a postman error.
Error
405 Method not allowed
I can sort this error out but I think the code is too verbose. Do you have any examples or a better way to do this?
Postman request
{
"email":"user#gmail.com",
"password":"Passw0rd",
"username":"user4",
"roles":["user"],
"firstname":"user",
"lastname":"Lee",
"phonenumber":"12345"
}
postman url
https://localhost:4200/api/accounts/05ce20c6-e2c4-4d40-b364-85c03206d562
Update Users
[Route("accounts/{id}")]
[HttpPut]
public async Task<IActionResult> UpdateUser(string id, [FromBody] RegistrationViewModel model)
{
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
var user = await _userManager.FindByIdAsync(id);
if (user == null)
{
return NotFound();
}
var userRoles = await _userManager.GetRolesAsync(user);
IdentityResult roleRemoveResult = await _userManager.RemoveFromRolesAsync(user, userRoles);
if (!roleRemoveResult.Succeeded)
{
ModelState.AddModelError("", "Failed to remove roles");
return BadRequest(ModelState);
}
IdentityResult roleAddResult = await _userManager.AddToRolesAsync(user, model.Roles);
if (!roleAddResult.Succeeded)
{
ModelState.AddModelError("", "Failed to add roles");
return BadRequest(ModelState);
}
//finished the role removing and assinging new roles
IdentityResult passwordResult = await _userManager.ChangePasswordAsync(user, user.PasswordHash, model.Password);
user.Email = model.Email;
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.PhoneNumber = model.PhoneNumber;
user.UserName = model.UserName;
IdentityResult updateUser = await _userManager.UpdateAsync(user);
if (!updateUser.Succeeded)
{
ModelState.AddModelError("", "Failed to update a user");
return BadRequest(ModelState);
}
var newUser = new User_Role_ViewModel();
newUser.Id = id;
newUser.Email = model.Email;
newUser.FirstName = model.FirstName;
newUser.LastName = model.LastName;
newUser.UserName = model.UserName;
newUser.Roles = model.Roles;
newUser.PhoneNumber = model.PhoneNumber;
return Ok(newUser);
}

how to delete users including roles and users from AspnetRoleUsers

I am making a project using asp.net core 3.1 and I can't find the right source of deleting users including roles in Asp.net core 3.1 using Web.api
This is the code I have tried but seems like not appropriate but haven't tried yet. Do you have any ideas of how to realize that?
I want to appropriately check the error using Web Api functions such as statuscode or any error messages to the frontend.
[HttpPost, ActionName("Delete")]
public async Task<ActionResult> DeleteUser(string id)
{
var user = await _userManager.FindByIdAsync(id);
var rolesForUser = await _userManager.GetRolesAsync(user);
if (rolesForUser.Count() > 0)
{
foreach (var item in rolesForUser.ToList())
{
// item should be the name of the role
var result = await _userManager.RemoveFromRoleAsync(user, item);
}
}
await _userManager.DeleteAsync(user);
return OkResult(result);
}
You don't need to loop the roles and delete , you can use RemoveFromRolesAsync :
public virtual Task<IdentityResult> RemoveFromRolesAsync(TUser user, IEnumerable<string> roles);
And each operation will return IdentityResult which could be used to check the operation status :
if (User.Identity.IsAuthenticated)
{
try
{
var user = await _userManager.FindByIdAsync(id);
var roles= await _userManager.GetRolesAsync(user);
var result = await _userManager.RemoveFromRolesAsync(user, roles);
if (result.Succeeded)
{
var resultdelete = await _userManager.DeleteAsync(user);
if (result.Succeeded)
{
return Ok();
}
else
{
List<string> errors = new List<string>();
foreach (var error in result.Errors)
{
errors.Add(error.Description);
}
return BadRequest(errors);
}
}
else
{
List<string> errors = new List<string>();
foreach (var error in result.Errors)
{
errors.Add(error.Description);
}
return BadRequest(errors);
}
}
catch (Exception exception)
{
List<string> errors = new List<string>() { exception.Message };
return StatusCode(StatusCodes.Status500InternalServerError, errors);
}
}
But use database stored procedures with transaction is always a good choice .

I try to login with Microsoft account and it's giving this error message "a database operation failed while processing the request."

i am try to login with Microsoft Authentication in .net core application but it's giving me error Like
a database operation failed while processing the request
i am getting this error when i am try to execute below code
enter code here
public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
// GetAsync the information about the user from the external login provider
var fname = Request.Form["Input.FirstName"].ToList().First();
if (string.IsNullOrEmpty(fname))
{
ErrorMessage = "FirstName Name is Required.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
var Lname = Request.Form["Input.LastName"].ToList().First();
if (string.IsNullOrEmpty(Lname))
{
ErrorMessage = "LastName Name is Required.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
var pNumber = Request.Form["Input.PhoneNumber"].ToList().First();
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
ErrorMessage = "Error loading external login information during confirmation.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
//if (ModelState.IsValid)
//{
//Todo: set all required fields
var user = new User { UserName = Input.Email, Email = Input.Email,FirstName= fname, LastName=Lname,PhoneNumber=pNumber,IsActive=true };
var searchKey = Input.Email.Split("#").Last();
var organization = _userRepository.SearchOrganization(searchKey);
if (organization != null)
user.OrganizationId = organization.Id;
var result = await _userManager.CreateAsync(user);
//Todo: Set Registered role
//Todo: Detect and assign organization
if (result.Succeeded)
{
result = await _userManager.AddLoginAsync(user, info);
if (result.Succeeded)
{
_userManager.AddToRoleAsync(user, SmartRole.RegisteredUser).Wait();
_userManager.AddToRoleAsync(user, SmartRole.Anonymous).Wait();
user.IsAdmin =
_signInManager.UserManager.IsInRoleAsync(user, "Administrator").Result;
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
//}
LoginProvider = info.LoginProvider;
ReturnUrl = returnUrl;
return Page();
}
i am try to compare some code with database that time i am getting this error
public Model.Organization SearchOrganization(string searchKey)
{
return DbContext.Organizations.FirstOrDefault(x =>x.URL.Equals(searchKey,StringComparison.OrdinalIgnoreCase));
}

return login success from a web api to an mvc 4 application

my colleague and myself are working on an application form with login functionality the user logs in from the mvc 4 app and there details are submitted to the web api to be checked against the values held in the database once verified the web api returns a loginResult class that contains the error message (if any) and a bool for stating whether it has been successful or not.
at the mvc 4 application level the code below is used to submit the login details to the web api:
Login Action
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(AccountViewModel model)
{
if (!ModelState.IsValid) return View("Login", model);
await _client.PostAsJsonAsync("api/Applicant/CheckApplicant", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
var service = DependencyResolver.Current.GetService<IApplyService>();
var loginResult = service.GetLoginResult();
var loginSuccess = loginResult.LoginSuccess;
if (loginSuccess != null && (bool) loginSuccess)
{
FormsAuthentication.SetAuthCookie(model.Email, model.RememberMe);
return RedirectToRoute("Terms And Conditions");
}
return View("Login");
}
the login details are then received at the web api in this method:
Check Applicant Method
public String CheckApplicant(Applicant applicant)
{
Int32 passwordFailureTimeoutMins = Convert.ToInt32(System.Configuration.ConfigurationSettings.AppSettings["PasswordFailureTimeoutMins"]);
Int32 passwordFailureAttempts = Convert.ToInt32(System.Configuration.ConfigurationSettings.AppSettings["PasswordFailureAttempts"]);
ApplicantRepository applicantRepository = new ApplicantRepository();
Applicant applicantDB = applicantRepository.GetById(applicant.Email);
LoginResult loginResult = new LoginResult();
PasswordHelper passwordHelper = new PasswordHelper();
if (applicantDB == null)
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "Your password or login may not be correct.";
}
else
{
bool loginFailureCheck;
if (applicantDB.LoginFailureCount > passwordFailureAttempts)
{
System.TimeSpan diffResult = DateTime.Now.Subtract(Convert.ToDateTime(applicantDB.LastLoginFailure));
if (diffResult.Minutes < passwordFailureTimeoutMins)
{
loginFailureCheck = false;
}
else
{
loginFailureCheck = true;
}
}
else
{
loginFailureCheck = true;
}
if (passwordHelper.CheckPassword(applicant.Password, applicantDB.Password))
{
if(loginFailureCheck)
{
if(applicantDB.AccountActive)
{
loginResult.LoginSuccess = true;
loginResult.LoginError = "Login Successful.";
applicantDB.LastLoginFailure = null;
applicantDB.LastLoginSuccess = DateTime.Now;
applicantDB.LoginFailureCount = 0;
applicantRepository.Update(applicantDB);
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "This account has been permanently banned.";
}
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "This account is now temporarily disabled please wait " + passwordFailureTimeoutMins + " minutes before trying again";
applicantDB.LastLoginFailure = DateTime.Now;
applicantDB.LoginFailureCount = applicantDB.LoginFailureCount + 1;
applicantRepository.Update(applicantDB);
}
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "Your password or login may not be correct.";
applicantDB.LastLoginFailure = DateTime.Now;
applicantDB.LoginFailureCount = applicantDB.LoginFailureCount + 1;
applicantRepository.Update(applicantDB);
}
}
return JsonConvert.SerializeObject(loginResult);
}
as you can see it returns a JsonConvert.SerializeObject(loginResult).
when this is done the process returns to the Login ActionResult as above it then moves to the GetLoginResult() method as shown below:
GetLoginResult
public LoginResult GetLoginResult()
{
const string uri = "http://localhost:55830/api/Applicant/CheckApplicant";
using (var httpClient = new HttpClient())
{
var response = httpClient.GetStringAsync(uri);
return JsonConvert.DeserializeObject<LoginResult>(response.Result);
}
}
when it get to this point it returns an error 405 method not allowed.
How do I consume the loginResult at the mvc 4 app level and what is the best way of sending the loginResult from the web api?
Any advice would be greatly appreciated.
Not sure what exactly you are trying to do but are you making a GET to read the result of the previous POST? You can read the response message of POST to get the result, like this.
public async Task<ActionResult> Login(AccountViewModel model)
{
if (!ModelState.IsValid) return View("Login", model);
var message = await _client.PostAsJsonAsync
("api/Applicant/CheckApplicant", model);
message.EnsureSuccessStatusCode();
LoginResult result = await message.Content.ReadAsAsync<LoginResult>();
// do other stuff here
}
Change the web API action method to return LoginResult directly. The framework will serialize it for you.
public LoginResult CheckApplicant(Applicant applicant)
{
}