Anders G. Nordby

Lead Consultant at Itera

Monthly Archives: November 2014

ASP.Net MVC 4.5 OWIN: Simple Roles Management

I find it somewhat strange that the built in templates in Visual Studio do not include some rudimentary system for managing users and roles. Asking my friend Google, I was pointed to this article: Working with Roles in ASP.NET MVC 4+ This looked good, and I eagerly entered this into a small test project. Alas, I was not able to make it work… So I went searching for how to create roles and users, and armed with this new knowledge, I was able to modify the mentioned example into working code.

Start by creating a new ASP.NET Web Application in Visual Studio 2013. You’ll get this familiar dialog:
new-aspnet-project

Before you go any further, click the Change Authentication button, and make sure that you have selected the Individual User Accounts option (this should be the default, but it’s wise to make sure nonetheless):
change-authentication

Add the following methods to your AccountController class:

[Authorize(Roles = "Admin")]
public ActionResult RoleCreate()
{
    return View();
}

[Authorize(Roles = "Admin")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RoleCreate(string roleName)
{
    using (var context = new ApplicationDbContext())
    {
        var roleStore = new RoleStore<IdentityRole>(context);
        var roleManager = new RoleManager<IdentityRole>(roleStore);

        roleManager.Create(new IdentityRole(roleName));
        context.SaveChanges();
    }
            
    ViewBag.ResultMessage = "Role created successfully !";
    return RedirectToAction("RoleIndex", "Account");
}

[Authorize(Roles = "Admin")]
public ActionResult RoleIndex()
{
    List<string> roles;
    using (var context = new ApplicationDbContext())
    {
        var roleStore = new RoleStore<IdentityRole>(context);
        var roleManager = new RoleManager<IdentityRole>(roleStore);

        roles = (from r in roleManager.Roles select r.Name).ToList();
    }

    return View(roles.ToList());
}

[Authorize(Roles = "Admin")]
public ActionResult RoleDelete(string roleName)
{
    using (var context = new ApplicationDbContext())
    {
        var roleStore = new RoleStore<IdentityRole>(context);
        var roleManager = new RoleManager<IdentityRole>(roleStore);
        var role = roleManager.FindByName(roleName);

        roleManager.Delete(role);
        context.SaveChanges();
    }

    ViewBag.ResultMessage = "Role deleted succesfully !";
    return RedirectToAction("RoleIndex", "Account");
}

[Authorize(Roles = "Admin")]
public ActionResult RoleAddToUser()
{
    List<string> roles;
    List<string> users;
    using (var context = new ApplicationDbContext())
    {
        var roleStore = new RoleStore<IdentityRole>(context);
        var roleManager = new RoleManager<IdentityRole>(roleStore);

        var userStore = new UserStore<ApplicationUser>(context);
        var userManager = new UserManager<ApplicationUser>(userStore);

        users = (from u in userManager.Users select u.UserName).ToList();
        roles = (from r in roleManager.Roles select r.Name).ToList();
    }

    ViewBag.Roles = new SelectList(roles);
    ViewBag.Users = new SelectList(users);
    return View();
}

[Authorize(Roles = "Admin")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RoleAddToUser(string roleName, string userName)
{
    List<string> roles;
    List<string> users;
    using (var context = new ApplicationDbContext())
    {
        var roleStore = new RoleStore<IdentityRole>(context);
        var roleManager = new RoleManager<IdentityRole>(roleStore);

        var userStore = new UserStore<ApplicationUser>(context);
        var userManager = new UserManager<ApplicationUser>(userStore);

        users = (from u in userManager.Users select u.UserName).ToList();

        var user = userManager.FindByName(userName);
        if (user == null)
            throw new Exception("User not found!");

        var role = roleManager.FindByName(roleName);
        if (role == null)
            throw new Exception("Role not found!");

        if (userManager.IsInRole(user.Id, role.Name))
        {
            ViewBag.ResultMessage = "This user already has the role specified !";
        }
        else
        {
            userManager.AddToRole(user.Id, role.Name);
            context.SaveChanges();

            ViewBag.ResultMessage = "Username added to the role succesfully !";
        }

        roles = (from r in roleManager.Roles select r.Name).ToList();
    }

    ViewBag.Roles = new SelectList(roles);
    ViewBag.Users = new SelectList(users);
    return View();
}

[Authorize(Roles = "Admin")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult GetRoles(string userName)
{
    if (!string.IsNullOrWhiteSpace(userName))
    {
        List<string> userRoles;
        List<string> roles;
        List<string> users;
        using (var context = new ApplicationDbContext())
        {
            var roleStore = new RoleStore<IdentityRole>(context);
            var roleManager = new RoleManager<IdentityRole>(roleStore);

            roles = (from r in roleManager.Roles select r.Name).ToList();

            var userStore = new UserStore<ApplicationUser>(context);
            var userManager = new UserManager<ApplicationUser>(userStore);

            users = (from u in userManager.Users select u.UserName).ToList();

            var user = userManager.FindByName(userName);
            if (user == null)
                throw new Exception("User not found!");

            var userRoleIds = (from r in user.Roles select r.RoleId);
            userRoles = (from id in userRoleIds
                let r = roleManager.FindById(id)
                select r.Name).ToList();
        }

        ViewBag.Roles = new SelectList(roles);
        ViewBag.Users = new SelectList(users);
        ViewBag.RolesForThisUser = userRoles;
    }

    return View("RoleAddToUser");
}

[HttpPost]
[Authorize(Roles = "Admin")]
[ValidateAntiForgeryToken]
public ActionResult DeleteRoleForUser(string userName, string roleName)
{
    List<string> userRoles;
    List<string> roles;
    List<string> users;
    using (var context = new ApplicationDbContext())
    {
        var roleStore = new RoleStore<IdentityRole>(context);
        var roleManager = new RoleManager<IdentityRole>(roleStore);

        roles = (from r in roleManager.Roles select r.Name).ToList();
                
        var userStore = new UserStore<ApplicationUser>(context);
        var userManager = new UserManager<ApplicationUser>(userStore);

        users = (from u in userManager.Users select u.UserName).ToList();

        var user = userManager.FindByName(userName);
        if (user == null)
            throw new Exception("User not found!");

        if (userManager.IsInRole(user.Id, roleName))
        {
            userManager.RemoveFromRole(user.Id, roleName);
            context.SaveChanges();

            ViewBag.ResultMessage = "Role removed from this user successfully !";
        }
        else
        {
            ViewBag.ResultMessage = "This user doesn't belong to selected role.";                    
        }

        var userRoleIds = (from r in user.Roles select r.RoleId);
        userRoles = (from id in userRoleIds
                        let r = roleManager.FindById(id)
                        select r.Name).ToList();
    }
     
    ViewBag.RolesForThisUser = userRoles;
    ViewBag.Roles = new SelectList(roles);
    ViewBag.Users = new SelectList(users);
    return View("RoleAddToUser");
}

Now, its time to create the necessary views. These should all be placed in the Views/Account folder:

@{
    ViewBag.Title = "RoleIndex";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<p>&nbsp;</p>
<div class="spacerBody">
    @Html.ActionLink("Create New Role", "RoleCreate") | @Html.ActionLink("Add Role to User", "RoleAddToUser")
    <h2>Role index</h2>
    @foreach (string s in Model)
    {
        <p>
            @s
            <span onclick=" return confirm('Are you sure to delete?') ">
                <a href="/Account/RoleDelete?RoleName=@s" class="delLink">Delete</a>
            </span>
        </p>
    }
</div>
@{
    ViewBag.Title = "RoleAddToUser";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="spacerBody">
    <p>&nbsp;</p>
    @Html.ActionLink("Create New Role", "RoleCreate") | @Html.ActionLink("Roles", "RoleIndex") 

    <h2>Add role to user</h2>
    @using (Html.BeginForm("RoleAddToUser", "Account"))
    {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary(true)

        <div class="message-success">@ViewBag.ResultMessage</div>
        <p>
            Username : @Html.DropDownList("UserName", ViewBag.Users as SelectList)
            Role Name: @Html.DropDownList("RoleName", ViewBag.Roles as SelectList)
        </p>

        <input type="submit" value="Save" />
    }
    
    <h2>Remove role from user</h2>
    @using (Html.BeginForm("DeleteRoleForUser", "Account"))
    {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary(true)

        <p>
            Username : @Html.DropDownList("UserName", ViewBag.Users as SelectList)
            Role Name: @Html.DropDownList("RoleName", ViewBag.Roles as SelectList)
        </p>

        <input type="submit" value="Delete this user from Role" />
    }
    
    <h2>List roles for user</h2>
    @using (Html.BeginForm("GetRoles", "Account"))
    {
        @Html.AntiForgeryToken()
        <p>
            Username : @Html.DropDownList("UserName", ViewBag.Users as SelectList)
            <input type="submit" value="Get Roles for this User" />
        </p>
    }

    @if (ViewBag.RolesForThisUser != null)
    {
        <text>
            <h3>Roles for this user </h3>
            <ol>
                @foreach (string s in ViewBag.RolesForThisUser)
                {
                    <li>@s</li>
                }
            </ol>
        </text>
    }
</div>
@{
    ViewBag.Title = "Create Role";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="spacerBody">
    <p>&nbsp;</p>
    @Html.ActionLink("Roles", "RoleIndex") | @Html.ActionLink("Add Role to User", "RoleAddToUser") 
    <h2>Role Create</h2>

    @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary(true)

        <div>
            Role name
        </div>
        <p>
            @Html.TextBox("RoleName")
        </p>
        <input type="submit" value="Save" />
    }
</div>

A final tip before you start up your application: When you run your application for the first time, you will be able to register a user (with an email and a password), but there will not exist any roles in the application yet, so how can you make yourself member of the Admin role? I solved this by pasting the following code into the HomeController.cs file, running the application once, and then deleting the code afterwards:

using (var context = new ApplicationDbContext())
{
    var roleStore = new RoleStore<IdentityRole>(context);
    var roleManager = new RoleManager<IdentityRole>(roleStore);

    roleManager.Create(new IdentityRole("Admin"));

    var userStore = new UserStore<ApplicationUser>(context);
    var userManager = new UserManager<ApplicationUser>(userStore);

    var user = userManager.FindByEmail("my.email@somewhere.com");
    userManager.AddToRole(user.Id, "Admin");
    context.SaveChanges();
}

Once you’ve given yourself the Admin role, all these options will become available to you.

The role management shown here is really simplistic, but for a simple demo application it will certainly do the job – and the code will teach you what you could do in a more sophisticated solution.

Advertisements