MVC 5 Identity Update UserRoles - asp.net-mvc

I wrote this code:
using(var _db = new ApplicationDbContext())
{
string roleName = "Admin";
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
if(!roleManager.RoleExists(roleName))
{
var newRoleresult = roleManager.Create(new IdentityRole()
{
Name = roleName,
});
var userRole = new IdentityUserRole
{
UserId = System.Web.HttpContext.Current.User.Identity.GetUserId(),
RoleId = roleManager.FindByName(roleName).Id,
};
I just need to Save userRole to table AspNetUserRoles. How I may do it?

To associate a User with a Role, you need to use AddToRole Method of UserManager API:
public async Task<ActionResult> UserRole()
{
string roleName = "Admin";
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
if (!roleManager.RoleExists(roleName))
{
var newRoleresult = await roleManager.CreateAsync(new IdentityRole()
{
Name = roleName,
});
var result = await UserManager.AddToRoleAsync(
System.Web.HttpContext.Current.User.Identity.GetUserId(),
roleManager.FindByName(roleName).Name);
if (!result.Succeeded)
{
ModelState.AddModelError("", result.Errors.First().ToString());
}
}
return View(); // If you have
}

Related

Checking User Roles to Display

I recently added Identity to my ASP.NET project, but I'm having trouble checking user roles.
I originally create my Admin role in Startup.cs:
private void createRolesandUsers()
{
ApplicationDbContext context = new ApplicationDbContext();
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
if (!roleManager.RoleExists("Admin"))
{
var role = new Microsoft.AspNet.Identity.EntityFramework.IdentityRole();
role.Name = "Admin";
roleManager.Create(role);
var user = new ApplicationUser();
user.UserName = "admin";
user.Email = "admin#tpms.com";
string userPWD = "********";
var chkUser = UserManager.Create(user, userPWD);
if (chkUser.Succeeded)
{
var result1 = UserManager.AddToRole(user.Id, "Admin");
}
}
}
In my UserController.cs, I have a function to check if the user is an admin:
public Boolean isAdminUser()
{
if (User.Identity.IsAuthenticated)
{
var user = User.Identity;
ApplicationDbContext context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var s = UserManager.GetRoles(user.GetUserId());
if (s[0].ToString() == "Admin")
{
return true;
}
else
{
return false;
}
}
return false;
}
However, I can't seem to find a way to access the isAdminUser() function from both my Views and my Controllers.
I've done a little bit of research the IsUserInRole() function, but when I tried:
#if (Roles.IsUserInRole(User.Identity.Name, "Admin")) { Html.ActionLink("Edit", "Edit", new { id=item.GuestID }); }
The if statement always returns false.
Try to use HttpContext.Current.User.IsInRole("Admin"); as Roles.IsUserInRole related to old membership provider under System.Web.Security namespace and need roleManager provider configuration in web.config.
#if(HttpContext.Current.User.IsInRole("Admin"))
{
Html.ActionLink("Edit", "Edit", new { id = item.GuestID });
}
Another way is to use UserManager
userManager.IsInRole("userId","Admin")

add role in database in asp mvc identity

i need to when user regiter add in tabel AspNetRole add user id and role id .
but when i create a user show me this error .
how can i insert role in database ?
/*************************************************************************************************/
identityconfig :
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));
}
}
public static class SecurityRole
{
public const string Admin = "admin";
public const string Accounting = "accounting";
}
StartupAuth :
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
AccountController :
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
}
private set
{
_roleManager = value;
}
}
public async Task<ActionResult> Register(RegisterViewModel model, HttpPostedFileBase IamgeProfile)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Username, Email = model.Email };
user.Name = model.Name;
user.Family = model.Family;
user.Address = model.Address;
user.BankName = model.BankName;
user.City = model.City;
user.Ostan = model.Ostan;
user.PhoneNumber = model.PhoneNumber;
user.HomeNumber = model.HomeNumber;
user.ShabaNo = model.ShabaNo;
user.PostaCode = model.PostaCode;
user.NationalCode = model.NationalCode;
if (IamgeProfile != null)
{
IamgeProfile = Request.Files[0];
var ext = System.IO.Path.GetExtension(IamgeProfile.FileName);
if (ext == ".jpeg" || ext == ".jpg" || ext == ".png")
{
string filename = model.Name + model.Family + model.NationalCode + ext;
IamgeProfile.SaveAs(Server.MapPath(#"~/Images/UserImageProfile/" + filename));
user.IamgeProfile = filename;
}
}
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
await UserManager.AddToRoleAsync(user.Id, role: SecurityRole.Accounting);
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, "Confirm your account", "Please confirm your account by clicking this link: link");
ViewBag.Link = callbackUrl;
return View("DisplayEmail");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
To add a role into AspNetRoles you can do this in your Seed() or other startup method:
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);
}
https://msdn.microsoft.com/en-us/library/dn613057(v=vs.108).aspx

MVC 5: On password change using UserManger, Invalid length for a Base-64 char array or string

In my MVC(5.1) application. I wanted to add password change.
This is what I have done,
public class AccountController : Controller
{
private readonly ILicenserepository _licenserepository;
private readonly IUserRepository _userRepository;
public AccountController(ILicenserepository licenserepository, IUserRepository userRepository)
{
_licenserepository = licenserepository;
_userRepository = userRepository;
//UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new DatePickerDbContext()));
....
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(ManageUserViewModel model)
{
bool hasPassword = HasPassword();
ViewBag.HasLocalPassword = hasPassword;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasPassword)
{
if (ModelState.IsValid)
{
string userId = User.Identity.GetUserId();
IdentityResult result = UserManager.ChangePassword(userId, model.OldPassword, model.NewPassword);
if (result.Succeeded)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
}
else
{
AddErrors(result);
}
}
}
else
{
// User does not have a password so remove any validation errors caused by a missing OldPassword field
ModelState state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid)
{
IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
if (result.Succeeded)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
}
else
{
AddErrors(result);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
}
When I run the application I get this error on browser
Invalid length for a Base-64 char array or string.
at line
IdentityResult result = UserManager.ChangePassword(userId, model.OldPassword, model.NewPassword);
I don't know what's wrong.
Is it because I haven't initialized my UserManger in constructor?
when I inspect the values in userId, model.OldPassword and model.NewPassword, all the values are as I expect. userId holds userId value, oldpassword holds oldpassowrd value and new password holds newpassword value provided from user.
It was my stupid mistake
I had created User like this before
var user = new ApplicationUser
{
FirstName = model.FirstName,
LastName = model.Lastname,
Phone = model.Phone,
Email = model.EmailId,
Company = model.Company,
PasswordHash = model.ConfirmPassword
UserName = model.UserName,
DateTimeRegistered = DateTime.UtcNow,
License = model.SelectedLicense,
IsApproved = true,
};
var result = UserManager.Create(user);
Here, the password would not be hashed and be saved as exact string user provides.
That was creating error.
should have provided password while creating the user like
var user = new ApplicationUser
{
FirstName = model.FirstName,
LastName = model.Lastname,
Phone = model.Phone,
Email = model.EmailId,
Company = model.Company,
UserName = model.UserName,
DateTimeRegistered = DateTime.UtcNow,
License = model.SelectedLicense,
IsApproved = true,
};
var result = UserManager.Create(user,model.ConfirmPassword);

Why is UserManager.Find() returning null if my UserName is email based?

I'm trying to implement email address based usernames in AspNet.Identity for MVC5, but I'm having trouble with the UserManager finding my user.
public UserManager<ApplicationUser> UserManager { get; private set; }
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
UserManager.UserValidator = new UserValidator<ApplicationUser>(UserManager)
{
AllowOnlyAlphanumericUserNames = false
};
}
In my login post method:
var user = await UserManager.FindAsync(model.UserName, model.Password);
user is null.
Am I using the wrong method to find my user by username and password?
Even if I use
var db = new ApplicationDBContext();
var user = db.Users.Find(model.UserName);
or
var db = new ApplicationDBContext();
var user = db.Users.FirstOrDefault(u => u.UserName == model.UserName);
I get a null
UPDATE
It looks like I'm getting null, because the users I'm trying to seed aren't being seeded. Anyone know why?
This is my seed for the users in the Configuration.cs (migrations):
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var users = new List<ApplicationUser>()
{
new ApplicationUser { UserName = "batman#email.com", IsActive = true },
new ApplicationUser { UserName = "superman#email.com", IsActive = true },
new ApplicationUser { UserName = "wonderwoman#email.com", IsActive = false }
};
users.ForEach(i => manager.Create(i, "password"));
If I seed the users with non-email UserNames, the seed goes through with no problem:
new ApplicationUser { UserName = "batman", IsActive = true },
new ApplicationUser { UserName = "superman", IsActive = true },
new ApplicationUser { UserName = "wonderwoman", IsActive = false }
Got it. I needed to change the validator in my seed:
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false
};
var users = new List<ApplicationUser>()
{
new ApplicationUser { UserName = "batman#email.com", IsActive = true },
new ApplicationUser { UserName = "superman#email.com", IsActive = true },
new ApplicationUser { UserName = "wonderwoman#email.com", IsActive = false }
};
users.ForEach(i => manager.Create(i, "December 2013"));
After this, I was able to seed my email-based UserNames.
I left this in my AccountController for adding users:
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
UserManager.UserValidator = new UserValidator<ApplicationUser>(UserManager)
{
AllowOnlyAlphanumericUserNames = false
};
}
Verify you have added Database Init Strategy Or doing manual updates.
e.g. [Database Init Strategy]
Database.SetInitializer<ApplicationDbContext>(new System.Data.Entity.MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());

MVC 5 Seed Users and Roles

I have been playing about with the new MVC 5, I have a few models, controller and views setup using code first migrations.
My question is how do I seed users and roles? I currently seed some reference data in my Seed method in Configuration.cs. But it looks to me that the user and roles tables are not created until something first hits the AccountController.
I currently have two connection strings so I can separate my data from my authentication into different databases.
How can I get the user, roles, etc tables populate along with my others? And not when the account controller is hit?
Here is example of usual Seed approach:
protected override void Seed(SecurityModule.DataContexts.IdentityDb context)
{
if (!context.Roles.Any(r => r.Name == "AppAdmin"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "AppAdmin" };
manager.Create(role);
}
if (!context.Users.Any(u => u.UserName == "founder"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser {UserName = "founder"};
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "AppAdmin");
}
}
I used package-manager "update-database". DB and all tables were created and seeded with data.
It's a small addition, but to anyone having the "UserId not found." message when trying to seed: (Tom Regan had this question in the comments, and I was stuck on it myself for a while)
This means that the manager.Create(user, "ChangeItAsap!") was not successful.
This might have a different reason, but for me it was because my password was not succeeding its validation.
I had a custom passwordvalidator, which was not being called when seeding the database, so the validation rules i was used to (minlength 4 instead of default 6) did not apply. Make sure your password (and all other fields for that matter) is passing validation.
This is my method base on Valin answer, I have added roles in db and added password for user. This code is placed in Seed() method in Migrations>Configurations.cs.
// role (Const.getRoles() return string[] whit all roles)
var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
for (int i = 0; i < Const.getRoles().Length; i++)
{
if (RoleManager.RoleExists(Const.getRoles()[i]) == false)
{
RoleManager.Create(new IdentityRole(Const.getRoles()[i]));
}
}
// user
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var PasswordHash = new PasswordHasher();
if (!context.Users.Any(u => u.UserName == "admin#admin.net"))
{
var user = new ApplicationUser
{
UserName = "admin#admin.net",
Email = "admin#admin.net",
PasswordHash = PasswordHash.HashPassword("123456")
};
UserManager.Create(user);
UserManager.AddToRole(user.Id, Const.getRoles()[0]);
}
Here i have an very easy,clean and smooth solution.
protected override void Seed(UserContext context)
{
//Step 1 Create the user.
var passwordHasher = new PasswordHasher();
var user = new IdentityUser("Administrator");
user.PasswordHash = passwordHasher.HashPassword("Admin12345");
user.SecurityStamp = Guid.NewGuid().ToString();
//Step 2 Create and add the new Role.
var roleToChoose = new IdentityRole("Admin");
context.Roles.Add(roleToChoose);
//Step 3 Create a role for a user
var role = new IdentityUserRole();
role.RoleId = roleToChoose.Id;
role.UserId = user.Id;
//Step 4 Add the role row and add the user to DB)
user.Roles.Add(role);
context.Users.Add(user);
}
protected override void Seed(ApplicationDbContext context)
{
SeedAsync(context).GetAwaiter().GetResult();
}
private async Task SeedAsync(ApplicationDbContext context)
{
var userManager = new ApplicationUserManager(new UserStore<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context));
var roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole, int, ApplicationUserRole>(context));
if (!roleManager.Roles.Any())
{
await roleManager.CreateAsync(new ApplicationRole { Name = ApplicationRole.AdminRoleName });
await roleManager.CreateAsync(new ApplicationRole { Name = ApplicationRole.AffiliateRoleName });
}
if (!userManager.Users.Any(u => u.UserName == "shimmy"))
{
var user = new ApplicationUser
{
UserName = "shimmy",
Email = "shimmy#gmail.com",
EmailConfirmed = true,
PhoneNumber = "0123456789",
PhoneNumberConfirmed = true
};
await userManager.CreateAsync(user, "****");
await userManager.AddToRoleAsync(user.Id, ApplicationRole.AdminRoleName);
}
}
Looks like they changes the way authentication works in MVC5, changed my Global.asax.cs to the following did the trick!
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Threading.Tasks;
using MvcAuth.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System.Threading;
using Microsoft.AspNet.Identity.EntityFramework;
namespace MvcAuth
{
public class MvcApplication : System.Web.HttpApplication
{
async Task<bool> AddRoleAndUser()
{
AuthenticationIdentityManager IdentityManager = new AuthenticationIdentityManager(
new IdentityStore(new ApplicationDbContext()));
var role = new Role("Role1");
IdentityResult result = await IdentityManager.Roles.CreateRoleAsync(role, CancellationToken.None);
if (result.Success == false)
return false;
var user = new ApplicationUser() { UserName = "user1" };
result = await IdentityManager.Users.CreateLocalUserAsync(user, "Password1");
if (result.Success == false)
return false;
result = await IdentityManager.Roles.AddUserToRoleAsync(user.Id, role.Id, CancellationToken.None);
return result.Success;
}
protected async void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
bool x = await AddRoleAndUser();
}
}
}
write this code in your Migration Configuration.
note: Use ApplicationDbContext in Configuration Class.
internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = false;
}
protected override void Seed(ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
context.Roles.AddOrUpdate(p =>
p.Id,
new IdentityRole { Name = "Admins"},
new IdentityRole { Name = "PowerUsers" },
new IdentityRole { Name = "Users" },
new IdentityRole { Name = "Anonymous" }
);
}
}

Resources