MVC 5 create user using Identity 2 in synchronous way - asp.net-identity-2

I'm trying to create new user and add him to selected role. I want to do it sync way, but always get stacked at point of creating in part ModelState. If I make it without ModelState then method will stack at point adminresult where is user created with UserManager. It looks like there is a problem with adding user to selected role, but I'm not sure. I'm using Identity 2. Is it possible to create user sync way or is it totally async process?
[HttpPost]
public ActionResult Create(User userViewModel, params string[] selectedRoles)
{
if (ModelState.IsValid)
{
var user = new User()
{
UserName = userViewModel.UserName,
Email = userViewModel.Email,
FirstName = userViewModel.FirstName,
LastName = userViewModel.LastName,
Password = userViewModel.Password
};
var adminresult = UserManager.Create(user, userViewModel.Password); // without using ModelState stack here
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
var userStore = new UserStore<User>(context);
var userManager = new UserManager<User>(userStore);
var result = userManager.AddToRoles(user.Id, selectedRoles);
if (adminresult.Succeeded)
{
if (selectedRoles != null)
{
if (!result.Succeeded)
{
ModelState.AddModelError("", result.Errors.First());
// gets all names of roles to list
ViewBag.RoleId = new SelectList(RoleManager.Roles.ToList(), "Name", "Name");
return View("_Create");
}
}
return RedirectToAction("UserWizardIndex");
}
return View("_Create");
}

I would recommend you to use group based roles instead of giving multiple roles at login.
Your a sync will work fine in this way if single role is at login..
one thing that I saw in your code is if you have selected multiple
roles why there isn't any way to add every role against that user...
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var roleManager = new RoleManager<IdentityRole>
(
new RoleStore<IdentityRole>
(
new ApplicationDbContext()
)
);
if (!roleManager.RoleExists(model.RoleName))
{
roleManager.Create(new IdentityRole(model.RoleName));
}
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var role = Db.GetUserRoleId(model.RoleName);
var strRole = role.FirstOrDefault().ToList();
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var userInfo = new UserInformation
{
FirstName = model.FirstName,
LastName = model.LastName,
GUID = user.Id,
RoleId = model.RoleId
};
Db.UserInformations.Add(userInfo);
UserManager.AddToRoles(userInfo.GUID, model.RoleName);
await UserManager.UpdateSecurityStampAsync(user.Id);
Db.SaveChanges();
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);
}

Related

Can`t login with seeded database configuration using asp.net identity

I have a problem with login, even though i see the tables are filled with my seeded user info from Configuration.cs:
protected override void Seed(www.Models.ApplicationDbContext context)
{
if (!context.Roles.Any(x => x.Name == "admin"))
{
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
var role = new IdentityRole { Name = "admin" };
roleManager.Create(role);
}
if (!context.Users.Any(x => x.UserName == "admin" && x.Email == "admin#admin.com"))
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var user = new ApplicationUser { UserName = "admin", Email = "admin#admin.com" };
var hasher = new PasswordHasher();
userManager.Create(user, "MySecret5");
userManager.AddToRole(user.Id, "admin");
}
}
and when i try to login i get error "Invalid login attempt".
What am i missing?
EDIT:
Im in the process of learning all stuff about asp.net so im pretty big noob now :( so i found this example to be working for me, and if anyone else needs it here it is:
protected override void Seed(www.Models.ApplicationDbContext context)
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
if (!context.Users.Any(x => x.UserName == "admin#v.com"))
{
var user = new ApplicationUser { UserName = "admin#v.com", Email = "admin#v.com" };
userManager.Create(user, "Password5%");
context.Roles.AddOrUpdate(x => x.Name, new IdentityRole { Name = "admin" });
context.SaveChanges();
userManager.AddToRole(user.Id, "admin");
}
}
And thanks for all your help and time.
It seems that the problem with logging in with seeded users is associated with MVC inaccuracy, look at:
var result = await SignInManager.PasswordSignInAsync(model.Emali, model.Password, model.RememberMe, shouldLockout: false);
if we seed this user:
var user = new ApplicationUser { UserName = "SomeName", Email = "admin#v.com" };
result will be == false, but if we change model.Emali in result to model.UserName then login end with success - of course now when we log in, we must give the UserName e.g:
UserName: SomeName;
Passwort: Password5%;
This worked flawlessly for me.
protected override void Seed(www.Models.ApplicationDbContext context)
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
if (!context.Users.Any(x => x.UserName == "admin#v.com"))
{
var user = new ApplicationUser { UserName = "admin#v.com", Email = "admin#v.com" };
userManager.Create(user, "Password5%");
context.Roles.AddOrUpdate(x => x.Name, new IdentityRole { Name = "admin" });
context.SaveChanges();
userManager.AddToRole(user.Id, "admin");
}
}

How to retrive profile photo,email from facebook graph version V 2.4 in asp.net MVC 5

i need to facebook profile photo and email in purpose of asp.mvc 5 web application. but facebook graph api version 2.4 email permission accessed. but .net mvc 5 code email value is null.and profile photo.
startup.Auth
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = "1655122338065609",
AppSecret = "5e858655ce82fad864e3991ae00db87a"
};
facebookAuthenticationOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
ExternalLoginCallback
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
var externalIdentity = HttpContext.GetOwinContext().Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);
var email = emailClaim.Value;
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName=loginInfo.DefaultUserName,Email=loginInfo.Email });
}
}
externallogoncallbacck method var emailcliam value is null return from startup.auth ???

MVC5 Identity Seed Users in database

I am getting an error that says: "UserId not found." when trying to seed multiple users into my database.
Here is my seed method:
protected override void Seed(newBestPlay.Models.ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
InitialCreate create = new InitialCreate();
create.Down();
create.Up();
context.Configuration.LazyLoadingEnabled = true;
if (!context.Roles.Any(r => r.Name == "Admin"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "Admin" };
manager.Create(role);
}
if (!context.Roles.Any(r => r.Name == "User"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "User" };
manager.Create(role);
}
if (!context.Users.Any(u => u.UserName == "user1"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser { UserName = "user1", Email = "email1" };
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "Admin");
}
if (!context.Users.Any(u => u.UserName == "user2"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser { UserName = "user2", Email = "email2" };
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "Admin");
}
}
It is failing on that last "manager.AddToRole" line. I figured out the second user isn't even getting added to the database, so it can't find a user.Id since it never got added.
Figured it out. It was not allowing dashes in my username. My username(email) has a dash in the domain part. I had to add in
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false };
into my IdentityConfig.cs file into the ApplicationUserManager constructor so it now looks like this:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false };
}
.....
add this into your seed method:
var manager = new UserManager<ApplicationUser>(store);
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
};

How can I change UserManager logic so that user must exist in database before they register

I am customizing the MVC5 registration process so that when users are registering they must enter two custom fields 'MyNewField1' and 'MyNewField2' which will be then checked against the user context to ensure if they exist in which case the registration can succeed by updating that current user.
public async Task<ActionResult> CustomRegister(CustomRegisterViewModel model)
{
if (ModelState.IsValid)
{
var context = new ApplicationDbContext();
ApplicationUser user = context.Users.Where(a => a.MyNewField1== model.MyNewField1& a.MyNewField2== a.MyNewField2).SingleOrDefault();
if(user != null)
{
var emailCheck = await UserManager.FindByNameAsync(model.Email);
if (emailCheck == null)
{
//We have found a user and email address has not been already assigned to another
//assign the email entered for this user in place of the username and email place
//holders and update the user before saving to the database
user.UserName = model.Email;
user.Email = model.Email;
var hasher = new PasswordHasher();
user.PasswordHash = hasher.HashPassword(model.Password);
context.SaveChanges();
var 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, "Budget Energy Email Verification", "Please confirm your account by clicking this link: link");
ViewBag.Link = callbackUrl;
ViewBag.Message = "Check your email and confirm your account, you must be confirmed before you can log in.";
return View("Info");
}
else
{
//This email address is already assigned to a user
return View(model);
}
}
else
{
//No user exists with these details so redisplay form
return View(model);
}
}
}
This method is passing off successfully and I am being informed that an email has been sent however when I click on this email link I am taken to an error page with the error being Invalid Token. Because I have changed the logic here do I have to create a token in a different manner?
I was able to solve this as follows:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> BillpayRegister(BillpayRegisterViewModel model)
{
if (ModelState.IsValid)
{
var context = new ApplicationDbContext();
ApplicationUser customer = context.Users.Where(a => a.MyNewField1 == model.MyNewField1 & a.MyNewField2 == model.MyNewField2).SingleOrDefault();
if(customer != null)
{
var emailCheck = await UserManager.FindByNameAsync(model.Email);
if (emailCheck == null)
{
//We have found a user and email address has not been already assigned to another
//assign the email entered for this user in place of the username and email place
//holders and update the user before saving to the database
var user = UserManager.FindById(customer.Id);
user.UserName = model.Email;
UserManager.SetEmail(user.Id, model.Email);
string hashedNewPassword = UserManager.PasswordHasher.HashPassword(model.Password);
user.PasswordHash = hashedNewPassword;
var result = UserManager.Update(user);
if (result.Succeeded)
{
var 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, "Email Verification", "Please confirm your account by clicking this link: link");
ViewBag.Link = callbackUrl;
ViewBag.Message = "Check your email and confirm your account, you must be confirmed before you can log in.";
return View("Info");
}
}
else
{
//This email address is already assigned to a user
return View(model);
}
}
else
{
//No user exists with these details so redisplay form
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}

Xamarin.Auth with Twitter

I am trying to implement login with Facebook and Twitter. I got it working with Facebook but don't know how to do it with Twitter. Are there any examples? My Facebook implementation is like this:
var auth = new OAuth2Authenticator(
clientId: "*****************",
scope: "email",
authorizeUrl: new System.Uri("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new System.Uri("http://www.facebook.com/connect/login_success.html"));
StartActivity(auth.GetUI(this));
auth.Completed += (senderFb, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
AccountStore.Create(this).Save(eventArgs.Account, "Facebook");
// Now that we're logged in, make a OAuth2 request to get the user's info.
var request = new OAuth2Request("GET", new System.Uri("https://graph.facebook.com/me"), null, eventArgs.Account);
request.GetResponseAsync().ContinueWith(t =>
{
if (!t.IsFaulted && !t.IsCanceled)
{
var obj = JsonValue.Parse(t.Result.GetResponseText());
if (obj != null)
{
var user = new UserProfile
{
FirstName = obj["first_name"],
LastName = obj["last_name"],
FacebookProfileLink = obj["link"],
FacebookToken = eventArgs.Account.Properties["access_token"],
Gender = obj["gender"] == "female" ? "Female" : "Male",
EmailAddress = obj["email"],
DisplayName = obj["name"],
Name = obj["name"],
LoginName = obj["email"]
};
SignUpUser(user);
}
}
}, uiScheduler);
}
};
You can use oauth1 like this.
this.Authenticator = new OAuth1Authenticator (ConsumerKey, ConsumerSecret, RequestTokenUrl, AuthorizeUrl, AccessTokenUrl, DummyCallBackUrl, (IDictionary<string, string> accountProperties) => {
string screen_name = "";
if (accountProperties.TryGetValue("screen_name", out screen_name)) {
Account a = new Account(screen_name, accountProperties);
AuthenticatorCompletedEventArgs e = new AuthenticatorCompletedEventArgs(a);
CompleteAuthentication(e);
}
return null;
});
twitter api dosen't fully support OAuth2

Resources