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);
}
Related
When I sign in with SignInAsync in ASP.NET Core Identity, RedirectToLocal is not authenticated.
If I log in without returning Url or go to allow anonymous action, it works fine, but when I redirect authenticate action return to the login page like the user never signs in. Still, I go to allow anonymous action and see the user sign in everything is okay.
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> LoginWithSms(string userId, string code, string returnUrl)
{
if (userId == null)
{
throw new ArgumentNullException(nameof(userId));
}
if (code == null)
{
throw new ArgumentNullException(nameof(code));
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
throw new ApplicationException(string.Format(ErrorConstant.UnableToLoadUser, userId));
}
var result = await _userManager.ConfirmEmailAsync(user, code);
if (!result.Succeeded)
{
return View("AccountError", this.GetErrorVm(AccountConstant.Persian.ConfirmSms, ErrorConstant.Persian.CodeWrong));
}
if (!user.PhoneNumberConfirmed)
{
user.PhoneNumberConfirmed = true;
_context.Users.Update(user);
_context.SaveChanges();
}
await _signInManager.SignInAsync(user, true);
await _setUserActivityLog.SetLogAsync(user.Id, AccountConstant.Persian.LoginToProfile);
return RedirectToLocal(string.IsNullOrEmpty(returnUrl) ? AccountConstant.Routes.ReturnUrlManageIndex : returnUrl);
}
redirect action:
[HttpGet]
[ActionDetail(menuCode: MenuConstant.ManageService.Code, name: "پاسخ دادن به تیکت")]
public async Task<IActionResult> TicketAnswer(long id)
{
var baseTicket = await _context.Tickets.Include(t => t.TicketType).Include(t => t.TicketRecords)
.ThenInclude(tr => tr.Person)
.SingleOrDefaultAsync(t => t.Id == id);
if (baseTicket == null)
{
return NotFound();
}
var vm = new ManageVm<TicketAnwserVm>
{
Entity = new TicketAnwserVm
{
QuickResponses = _context.QuickResponses.OrderBy(qr => qr.Title).Select(qr => new QuickResponseVm
{
Id = qr.Id,
Title = qr.Title
}),
Ticket = new TicketDisplayVm(baseTicket.StartDate)
{
Id = baseTicket.Id,
PersonId = baseTicket.PersonId,
State = baseTicket.State,
Subject = baseTicket.Subject,
TicketTypeName = baseTicket.TicketType.Name,
TicketRecords = baseTicket.TicketRecords.Join(_context.Users, tr => tr.PersonId,
u => u.PersonId,
(tr, u) => new TicketRecordVm(tr.Date)
{
Id = tr.Id,
PersonName = tr.Person.Name,
UserId = u.Id,
Content = tr.Content,
IsOwner = tr.IsOwner,
TicketId = tr.TicketId,
Status = tr.IsOwner ? TicketStatus.Out : TicketStatus.In
})
}
}
};
return View(vm);
}
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 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));
}
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
I have an mvc4 forms application that uses the simple membership OOTB account controller. I have a view model for the application where I was successfully able to retrieve the username after completing registration as follows:
this.UserName = HttpContext.Current.User.Identity.Name;
At the point this was working my registration method was as follows:
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, propertyValues: new
{
//Form defined values
Forename = model.Forename,
Surname = model.Surname,
Email = model.Email,
Password = model.Password,
Answer = model.SecretAnswer,
DOB = model.DOB,
//Auto defined values
JoinDate = DateTime.Today,
LastLogin = DateTime.Now,
CompanyID = 5,
ParticipationPoints = 0,
Privacy = 0,
IsDeleted = 0,
ImageURL = "/Images/user-holder.jpg"
});
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
After consultation with my customer it was decided that to prevent anyone from just registering on the internet they should already be contained with the usertable with the username value found as a pre existing user. So after this the registration was changed to:
Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
avm.Username = model.UserName;
avm.Forename = model.Forename;
avm.Surname = model.Surname;
avm.Email = model.Email;
avm.Password = model.Password;
avm.Answer = model.SecretAnswer;
avm.DOB = model.DOB;
avm.RegisterUser();
if (avm.StatusCode == "Success")
{
return RedirectToAction("Index", "Home");
}
else
{
//ModelState.AddModelError("", ErrorCodeToString(avm.StatusCode));
return View();
}
}
}
ViewModel
try
{
this.dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
userRepository = new Repository<MyUser>(dbcontext);
//Step 1 - Check User is in user table.
MyUser userCheck = userRepository.Get(u => u.Username == this.Username).ToList().FirstOrDefault();
if (userCheck == null)
{
StatusCode = "NoUserError";
return;
}
else
{
//Step 2 - Check user has not already registered
if (userCheck.Password != null || userCheck.Answer != null)
{
StatusCode = "AlreadyRegistered";
return;
}
}
//Step 3 - Check the email is valid and the password confirms to password length.
Regex expEmail = new Regex(#"^([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})(\]?)$");
if (!expEmail.IsMatch(this.Email))
{
StatusCode = "InvalidEmail";
return;
}
if (this.Password.Length < 8)
{
StatusCode = "InvalidPassword";
return;
}
//Encrypt the password to store in SQL Azure. It does not at this point have any encryption.
EncryptionUtils encryptor = new EncryptionUtils();
string encrytpedPassword = encryptor.Encrypt(this.Password);
//Form defined fields
userCheck.Username = this.Username;
userCheck.Password = encrytpedPassword;
userCheck.Forename = this.Forename;
userCheck.Surname = this.Surname;
userCheck.Email = this.Email;
userCheck.Answer = this.Answer;
userCheck.DOB = this.DOB;
//Automatically defined values
userCheck.JoinDate = DateTime.Today;
userCheck.LastLogin = DateTime.Now;
userCheck.CompanyID = 5;
userCheck.RoleID = 3;
userCheck.ParticipationPoints = 0;
userCheck.Privacy = 0;
userCheck.IsDeleted = false;
userCheck.ImageURL = "/Images/user-holder.jpg";
userRepository.Update(userCheck);
userRepository.SaveChanges();
StatusCode = "Success";
}
catch (Exception ex)
{
StatusCode = "Error";
return;
}
}
Now when I hit the home controller I am not able to access the HttpContext.Current.User.Identity.Name value. Has the authenticated username been stored elsewhere due to the changes?
Authentication cookie must be issued after registration success. Try,
if (avm.StatusCode == "Success")
{
FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("Index", "Home");
}
hope this helps.