I started a .net web forms project, the template already allows users to login and register, On the manage page there is an option to reset password. how can I add options to update FirstName and LastName?
This is the code to create a new user:
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text, FirstName = FirstName.Text, LastName = LastName.Text, PhoneNumber = PhoneNumber.Text };
IdentityResult result = manager.Create(user, Password.Text);
if (result.Succeeded)
{
signInManager.SignIn( user, isPersistent: false, rememberBrowser: false); //not needed
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response); //not needed
}
else
{
ErrorMessage.Text = result.Errors.FirstOrDefault();
}
this is how the form looks like:
This is how I solved it: hope it helps anybody.
var currentUserId = HttpContext.Current.User.Identity.GetUserId();
var context = new ApplicationDbContext();
var user = context.Users.FirstOrDefault(u => u.Id == currentUserId);
if (user != null)
{
if (FirstName.Text != "") user.FirstName = FirstName.Text;
if (LastName.Text != "") user.LastName = LastName.Text;
if (PhoneNumber.Text != "") user.PhoneNumber = PhoneNumber.Text;
if(Email.Text != "") user.Email = Email.Text;
}
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var result = userManager.Update(user);
context.SaveChanges();
Related
I'm writing api for the application
The task is to redirect to the profile page on the client after confirming the email. While email is not confirmed, I can not give access token to api.
At the moment a crutch lives on the client: username and password
temporarily stored locally, so that after the customer can make a hidden sign in.(what is not safe)
How can this problem be solved?
I have one not very nice idea: after registration give a access token and after on for each request check - emailConfirmed(bool)
But - perform an additional request each time ...
Small code example from back:
ApplicationOAuthProvider:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
var a = await userManager.FindByIdAsync(context.ClientId);
if (user == null)
{
context.SetError("invalid_grant", "Username or Password is incorrect.");
return;
}
if (!user.EmailConfirmed)
{
context.SetError("invalid_grant", "Email not confirmed.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
Send code on email:
[AllowAnonymous]
[HttpPost]
[Route("Users/{userId}/emailConfirmation")]
public async Task<IHttpActionResult> SendConfirmationCode(string userId)
{
if (userId == null)
{
return BadRequest("UserId were not transferred");
}
var user = await UserManager.FindByIdAsync(userId);
if (user == null)
{
return Content(HttpStatusCode.NotFound, "User not found");
}
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var url = $"{clientBaseUrl}confirm_email?userId={user.Id}&code={WebUtility.UrlEncode(code)}";
await MailHelper.SendConfirmationLinkOnEmail(url, user.Email);
return Content(HttpStatusCode.OK, new { Message = "Confirmation code was sent on email" });
}
Email confirmation by code:
[AllowAnonymous]
[HttpPost]
[Route("Users/{userId}/emailConfirmationCode")]
public async Task<IHttpActionResult> ConfirmEmail(string userId, [FromBody]EmailConfirmationDTO input)
{
if (userId == null || input == null)
{
return BadRequest("UserId or code were not transferred");
}
try
{
var isConfirmed = await UserManager.IsEmailConfirmedAsync(userId);
if (isConfirmed)
{
return Content(HttpStatusCode.Forbidden, new { Message = "This user already confirmed email" });
}
var result = await UserManager.ConfirmEmailAsync(userId, input.Code);
if (result.Succeeded)
{
var user = Db.Users.FirstOrDefaultAsync(u => u.Id == userId);
return Content(HttpStatusCode.OK, new { responseObj = user });
}
}
catch (Exception e)
{
// ignored
}
return Content(HttpStatusCode.InternalServerError, new { Message = "Error confirmation." });
}
ConfigureAuth:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(5),
#if (!DEBUG)
AllowInsecureHttp = false
#else
AllowInsecureHttp = true
#endif
};
How to change user password by admin in Asp core 2.x ?
or Change password with sms code
My sample code:
if (!ModelState.IsValid)
return View(model);
var user = await _userManager.FindByNameAsync(model.UserName);
if (user == null)
return RedirectToAction("Index");
if (model.smsCode == user.SmsCode)
{
user.PasswordHash = model.NewPassword;
IdentityResult result = await _userManager.UpdateAsync(user);
if (result.Succeeded)
{
}
}
error: save unhash pass in db
We should not update the user.PasswordHash with a plain text , we should use Hash instead .
var user = await _userManager.FindByNameAsync(model.UserName);
if(user == null){ /**/ }
if (model.smsCode != user.SmsCode){ /**/}
// compute the new hash string
var newPassword = _userManager.PasswordHasher.HashPassword(user,newpass);
user.PasswordHash = newPassword;
var res = await _userManager.UpdateAsync(user);
if (res.Succeeded) {/**/}
else { /**/}
I have implemented FormAuthentication in asp.net mvc 5 and create FormsAuthenticationticket on LogIn and it creates successfully but after few moments that cookie is showing in browser but in application it's getting null.
Please help to solve this issue.
Any help will be appreciated Thanks
LOGIN FORM
public ActionResult Login([Bind(Include = "Username, Password")] LoginModel loginModel, string ReturnUrl)
{
if (ModelState.IsValid)
{
Egov_Users eGov_Users = db.Egov_Users
.Where(p => p.UserType.Type != "O" && p.UserName == loginModel.Username)
.FirstOrDefault();
if (eGov_Users == null)
{
ModelState.AddModelError("", "Invalid username");
return View();
}
else
{
if (eGov_Users.Password != loginModel.Password)
{
ModelState.AddModelError("", "Invalid Password");
return View();
}
var loginDetail = new LoginDetails();
var serializer = new JavaScriptSerializer();
loginDetail.userID = eGov_Users.UserId;
loginDetail.username = eGov_Users.UserName;
loginDetail.firstName = eGov_Users.FirstName;
loginDetail.lastName = eGov_Users.LastName;
var userData = SerializeUserInfoInternal(loginDetail);
FormsAuthentication.SetAuthCookie(loginDetail.username, false);
var cookie = FormsAuthentication.GetAuthCookie(
FormsAuthentication.FormsCookieName, false);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var durationInHours = 8;
FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(
ticket.Version,
loginDetail.username,
DateTime.Now,
DateTime.Now.AddHours(durationInHours),
true,
userData);
// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(newTicket);
cookie.Value = encTicket;
Response.Cookies.Add(cookie);
int cookieSize = System.Text.UTF8Encoding.UTF8.GetByteCount(cookie.Values.ToString());
Session["CookieSize"] = cookieSize;
if (string.IsNullOrEmpty(ReturnUrl))
{
return RedirectToAction("Index", "Users");
}
}
}
return RedirectToAction("Login", "Login");
}
GLOBAL ASAX
protected void Application_PostAuthenticateRequest()
{
var ticket = GetTicketFromCurrentCookie();
if (ticket == null)
{
Global.WriteLog("Application_PostAuthenticateRequest", "ticket becomes null");
return;
}
var user = DeserializeUserInfoInternal(ticket.Name, ticket.UserData);
if (user == null)
{
return;
}
var principal = new AppUserPrincipal(user);
HttpContext.Current.User = principal;
}
private static FormsAuthenticationTicket GetTicketFromCurrentCookie()
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie == null)
{
Global.WriteLog("GetTicketFromCurrentCookie", "Cookie becomes null");
return null;
}
var ticket = FormsAuthentication.Decrypt(cookie.Value);
return ticket;
}
static LoginDetails DeserializeUserInfoInternal(string name, string userData)
{
var deserialize = new JavaScriptSerializer();
var loginDetails = deserialize.Deserialize<LoginDetails>(userData);
return loginDetails;
}
use below code to get the cookie value
HttpContext.Current.Request.Cookies.Get(".ASPXAUTH");
This is my ExternalLoginConfirmation task, that is the default code added when the project is created. I have added these lines to get the user claims:
user.Firstname = info.Principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.ToString();
user.Lastname = info.Principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.ToString();
user.Gender = info.Principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Gender)?.ToString();
However I'm not able to get the user profile image as it does not exist in ClaimTypes.
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return View("ExternalLoginFailure");
}
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user);
if (result.Succeeded)
{
result = await _userManager.AddLoginAsync(user, info);
if (result.Succeeded)
{
user.Firstname = info.Principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.ToString();
user.Lastname = info.Principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.ToString();
user.Gender = info.Principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Gender)?.ToString();
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
ViewData["ReturnUrl"] = returnUrl;
return View(model);
}
Note that info is missing ExternalPrincipal and the following functionality is not available either:
info.ExternalPrincipal.FindFirstValue("pictureUrl");
This is the soultion I'm using now:
var result = await _userManager.CreateAsync(user);
if (result.Succeeded)
{
result = await _userManager.AddLoginAsync(user, info);
if (result.Succeeded)
{
if (info.LoginProvider.ToLower().IndexOf("google") != -1)
{ await _userManager.AddClaimAsync(user, new Claim("GooglePlusId", info.ProviderKey));
try {
HttpClient client = new HttpClient();
HttpResponseMessage x = await client.GetAsync($"https://www.googleapis.com/plus/v1/people/{info.ProviderKey}?fields=image&key=YOUR_GOOGLE_PLUS_API_KEY");
dynamic img = Newtonsoft.Json.JsonConvert.DeserializeObject(await x.Content.ReadAsStringAsync());
user.PhotoLink = img.image.url;
db.SaveChanges();
}
catch { }
}
if (info.LoginProvider.ToLower().IndexOf("facebook") != -1)
{
user.PhotoLink = $"http://graph.facebook.com/{info.ProviderKey}/picture?type=square&width=50";
}
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
}
}
P.S.: this code should be added to ExternalLoginConfirmation action in AccountControllers controller
I came across a problem for seeding the database with Identity v2. I separated out the IdentityModel from the MVC5 project to my Data Access Layer where I setup EF Migrations as well. So I commented out the code which use inside "IdentityConfig.cs" to create initial user and put the code inside my seed database that looks like this
protected override void Seed(Repository.DataContext.IdentityDb context)
{
// var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
// var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
var owinContext = new OwinContext();
var userManager = owinContext.GetUserManager<ApplicationUserManager>();
var roleManager = owinContext.Get<ApplicationRoleManager>();
const string name = "admin#admin.com";
const string password = "Admin#123456";
const string roleName = "Admin";
// //Create Role Admin if it does not exist
var role = roleManager.FindByName(roleName);
if (role == null)
{
role = new IdentityRole(roleName);
var roleresult = roleManager.Create(role);
}
var user = userManager.FindByName(name);
if (user == null)
{
user = new ApplicationUser { UserName = name, Email = name };
var result = userManager.Create(user, password);
result = userManager.SetLockoutEnabled(user.Id, false);
}
// // Add user admin to Role Admin if not already added
var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name))
{
var result = userManager.AddToRole(user.Id, role.Name);
}
}
Now when I am running command update-database, I got an error
Value cannot be null.
Parameter name: manager
It looks like, I am getting null in these two lines of code
var userManager = owinContext.GetUserManager<ApplicationUserManager>();
var roleManager = owinContext.Get<ApplicationRoleManager>();
Any suggestion please?
This is the way to avoid using an OWIN context:
protected override void Seed(Repository.DataContext.IdentityDb context)
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var user = new ApplicationUser { UserName = "sallen" };
userManager.Create(user, "password");
roleManager.Create(new IdentityRole { Name = "admin" });
userManager.AddToRole(user.Id, "admin");
}
I got this working by using:
protected override void Seed(ApplicationDbContext context)
{
context.Configuration.LazyLoadingEnabled = true;
//var userManager = HttpContext.Current
// .GetOwinContext().GetUserManager<ApplicationUserManager>();
//var roleManager = HttpContext.Current
// .GetOwinContext().Get<ApplicationRoleManager>();
var roleStore = new RoleStore<ApplicationRole, int, ApplicationUserRole>(context);
var roleManager = new RoleManager<ApplicationRole, int>(roleStore);
var userStore = new UserStore<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context);
var userManager = new UserManager<ApplicationUser, int>(userStore);
...
Hi Under the Startup class please make sure that you have call
app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContextApplicationUserManager.Create);
app.CreatePerOwinContextApplicationSignInManager.Create);
app.CreatePerOwinContext(ApplicationRoleManager.Create);
Latest stuff is all async & uses Claims.
Here's what worked for me with migrations to add a super user if none exists ...
protected override void Seed(Holos.Service.Models.ApplicationDbContext context)
{
var email = "xxxx#xxxx.com";
var password = "xxxxx";
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new ApplicationUserManager(userStore);
var user = userManager.FindByEmailAsync(email).Result;
if (user == null)
{
var adminUser = new ApplicationUser() { Email = email, UserName = email };
var result = userManager.CreateAsync(adminUser, password);
result.Wait();
userManager.AddClaimAsync(adminUser.Id, new Claim("Read", "*")).Wait();
userManager.AddClaimAsync(adminUser.Id, new Claim("Create", "*")).Wait();
userManager.AddClaimAsync(adminUser.Id, new Claim("Update", "*")).Wait();
userManager.AddClaimAsync(adminUser.Id, new Claim("Delete", "*")).Wait();
userManager.AddClaimAsync(adminUser.Id, new Claim("UserType", "SuperUser")).Wait();
}
}