Creating The Family Page – Part 6, Role and User Management

This time we will add role management and subsequently give an administrator the ability to a manage (add/edit/delete) users. It might seem overkill to have roles on such a simple page, that will hold the content of a family of four. The idea is however that the kids can edit their own content, while mom and dad can edit everything, so roles will be useful. Again it might be overkill to implement management systems for that – we know the number of users and their roles are pretty much set in stone, so we could just hardcode everything. It is however pretty straight forward to implement user and role management and it also has an educational value for me.

The code presented here is heavily inspired by an ASP.NET Identity sample project from the team behind ASP.NET Identity. Unfortunately I haven’t been able to find that sample again – but here is a lot of smaller samples to get you started: http://www.asp.net/aspnet/samples/aspnet-identity

So, the agenda of the day:

  • Bootstrap the user and role system – Create an admin role and user (user zero)
  • Create role management CRUD operations in controller and views.
  • Create user management CRUD operations in controller and views.
  • Remove registration from the front page.

Lets get started.

Bootstrap the user and role system

The only persons allowed to use the user and role management systems are administrators. But in order to become an administrator your need to use the role management system. This is kind of a deadlock. To solve this, we will hardcode a first user into the system. In App_Start/IdentityConfig.cs we add the following code:

  public class ApplicationRoleManager : RoleManager
  {
    public ApplicationRoleManager(IRoleStorestring> roleStore)
      : base(roleStore)
    {
    }

    public static ApplicationRoleManager Create(IdentityFactoryOptions options, IOwinContext context)
    {
      var manager = new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get()));
      return manager;
    }
  }


  public class ApplicaitonDbInitializer : DropCreateDatabaseIfModelChanges
  {
    const string adminRoleName = "Admin";

    protected override void Seed(ApplicationDbContext context)
    {
      InitializeAdminRole(context);
      InitializeFirstUser(context);
      base.Seed(context);
    }

    void InitializeFirstUser(ApplicationDbContext context)
    {
      var userManager = HttpContext.Current.GetOwinContext().GetUserManager();
      var roleManager = HttpContext.Current.GetOwinContext().Get();
      const string name = "admin@admin.com";
      const string password = "Admin@123456";

      var user = userManager.FindByName(name);
      if (user == null)
      {
        user = new ApplicationUser { UserName = name, Email = name };
        userManager.Create(user, password);
        userManager.SetLockoutEnabled(user.Id, false);
      }

      // Add user admin to Role Admin if not already added
      var rolesForUser = userManager.GetRoles(user.Id);
      var role = roleManager.FindByName(adminRoleName);
      if (!rolesForUser.Contains(role.Name))
      {
        userManager.AddToRole(user.Id, role.Name);
      }
    }

    void InitializeAdminRole(ApplicationDbContext context)
    {
      var roleManager = HttpContext.Current.GetOwinContext().Get();

      //Create Role Admin if it does not exist
      var role = roleManager.FindByName(adminRoleName);
      if (role == null)
      {
        role = new IdentityRole(adminRoleName);
        roleManager.Create(role);
      }
    }
  }

 

So this code add the user “admin@admin.com” with the password “Admin@12345” and gives this user the role “Admin”.

Create role management

First we add a simple view model.

  public class RoleViewModel
  {
    public string Id { get; set; }

    [Required(AllowEmptyStrings = false)]
    public string RoleName { get; set; }
  }

 

And a controller for CRUD operations.

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Collections.Generic;

using TheFamilyPage;
using TheFamilyPage.Models;

namespace IdentitySample.Controllers
{
  [Authorize(Roles = "Admin")]
  public class RolesManagerController : Controller
  {
    public RolesManagerController()
    {
    }

    public ApplicationUserManager UserManager
    {
      get
      {
        return HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
      }
    }

    public ApplicationRoleManager RoleManager
    {
      get
      {
        return HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
      }
    }

    //
    // GET: /Roles/
    public ActionResult Index()
    {
      return View(RoleManager.Roles);
    }

    //
    // GET: /Roles/Details/5
    public async Task Details(string id)
    {
      if (id == null)
      {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      }
      var role = await RoleManager.FindByIdAsync(id);
      // Get the list of Users in this Role
      var users = new List<ApplicationUser>();

      // Get the list of Users in this Role
      foreach (var user in UserManager.Users.ToList())
      {
        if (await UserManager.IsInRoleAsync(user.Id, role.Name))
        {
          users.Add(user);
        }
      }

      ViewBag.Users = users;
      ViewBag.UserCount = users.Count();
      return View(role);
    }

    //
    // GET: /Roles/Create
    public ActionResult Create()
    {
      return View();
    }

    //
    // POST: /Roles/Create
    [HttpPost]
    public async Task Create(RoleViewModel roleViewModel)
    {
      if (ModelState.IsValid)
      {
        var role = new IdentityRole(roleViewModel.RoleName);
        var roleresult = await RoleManager.CreateAsync(role);
        if (!roleresult.Succeeded)
        {
          ModelState.AddModelError("", roleresult.Errors.First());
          return View();
        }
        return RedirectToAction("Index");
      }
      return View();
    }

    //
    // GET: /Roles/Edit/Admin
    public async Task Edit(string id)
    {
      if (id == null)
      {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      }
      var role = await RoleManager.FindByIdAsync(id);
      if (role == null)
      {
        return HttpNotFound();
      }
      RoleViewModel roleModel = new RoleViewModel { Id = role.Id, RoleName = role.Name };
      return View(roleModel);
    }

    //
    // POST: /Roles/Edit/5
    [HttpPost]

    [ValidateAntiForgeryToken]
    public async Task Edit([Bind(Include = "Name,Id")] RoleViewModel roleModel)
    {
      if (ModelState.IsValid)
      {
        var role = await RoleManager.FindByIdAsync(roleModel.Id);
        role.Name = roleModel.RoleName;
        await RoleManager.UpdateAsync(role);
        return RedirectToAction("Index");
      }
      return View();
    }

    //
    // GET: /Roles/Delete/5
    public async Task Delete(string id)
    {
      if (id == null)
      {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      }
      var role = await RoleManager.FindByIdAsync(id);
      if (role == null)
      {
        return HttpNotFound();
      }
      return View(role);
    }

    //
    // POST: /Roles/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task DeleteConfirmed(string id, string deleteUser)
    {
      if (ModelState.IsValid)
      {
        if (id == null)
        {
          return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var role = await RoleManager.FindByIdAsync(id);
        if (role == null)
        {
          return HttpNotFound();
        }
        IdentityResult result;
        if (deleteUser != null)
        {
          result = await RoleManager.DeleteAsync(role);
        }
        else
        {
          result = await RoleManager.DeleteAsync(role);
        }
        if (!result.Succeeded)
        {
          ModelState.AddModelError("", result.Errors.First());
          return View();
        }
        return RedirectToAction("Index");
      }
      return View();
    }
  }
}

And views to match the controller:

Create:

@model TheFamilyPage.Models.RoleViewModel

@{
    ViewBag.Title = "Create";
}

<h2>Create.</h2>


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

    <div class="form-horizontal">
        <h4>Role.</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Name)
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Edit:

@model TheFamilyPage.Models.RoleViewModel

@{
    ViewBag.Title = "Edit";
}

<h2>Edit.</h2>


@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Roles.</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Name)
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Delete:

@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole

@{
    ViewBag.Title = "Delete";
}

Delete.

Are you sure you want to delete

this Role? </h3>
<p>Deleting this Role will remove all users from this role. It will notdelete the users.

 

Role.


class="dl-horizontal">
            @Html.DisplayNameFor(model => model.Name)
        
            @Html.DisplayFor(model => model.Name)
        
    <!--dl>
    @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()

        <div class="form-actions no-color">
            <input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("Back to List", "Index")
        </div>
    }
</div>

Index:

@model IEnumerable<Microsoft.AspNet.Identity.EntityFramework.IdentityRole>

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>

        </th>
    </tr>

    @foreach (var item in Model)
    {
        
            
                @Html.DisplayFor(modelItem => item.Name)
            
            
                @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                @Html.ActionLink("Details", "Details", new { id = item.Id }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.Id })
            </td>
        </tr>
    }

</table>

Details:

@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole

@{
    ViewBag.Title = "Details";
}

<h2>Details.</h2>

<div>
    <h4>Roles.</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Name)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Name)
        </dd>
    </dl>
</div>
<h4>List of users in this role</h4>
@if (ViewBag.UserCount == 0)
{
    <hr />
    <p>No users found in this role.</p>
}

<table class="table">

    @foreach (var item in ViewBag.Users)
    {
        <tr>
            <td>
                @item.UserName
            </td>
        </tr>
    }
</table>
<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
    @Html.ActionLink("Back to List", "Index")
</p>



All of the above is taken direktly from the Identity sample application. This is NOT code I can take credit for.

Create user management

User management is completely analogue to role management –  I will not show the code here, but it is available on GitHub.

Remove anonymous registration and enable managament

In order to enable access to the users manager and roles manger, we add links to these pages in the _laout.cshtml file – so add the yellow lines:

@using System.Net.Mime
<!--DOCTYPE html>


    "utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")

</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("The Family Page", "Index", "Home", null, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                  @if (Request.IsAuthenticated && User.IsInRole("Admin"))
                  {
                    <li>@Html.ActionLink("Manage Roles", "Index", "RolesManager")</li>
                    <li>@Html.ActionLink("Manage Users", "Index", "UsersManager")</li>
                  }
                <!--ul>
                @Html.Partial("_LoginPartial")
            </div>
        </div>
    </div>
    <div class="container body-content">
        @RenderBody()

© @DateTime.Now.Year – My ASP.NET MediaTypeNames.Application

    

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

Then remove the possibility for anybody to register themselves – so remove the yellow line:

using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated)
{
    using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
    {
    @Html.AntiForgeryToken()

    <ul class="nav navbar-nav navbar-right">
        <li>
            @Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage" })
        </li>
        <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
    </ul>
    }
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
        <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
    </ul>
}

As always the complete code can be found here: https://github.com/iCodeIT/TheFamilyPage

 

Next time

Next time it is time to talk about content – the wish lists.

Advertisements

About Lund

Owner of iCodeIT, a software consulting company. I am primarily working the .NET development and architecture.
This entry was posted in ASP.NET identity, C#, HTML5, Web and tagged , , , , . Bookmark the permalink.

6 Responses to Creating The Family Page – Part 6, Role and User Management

  1. RA Joseph says:

    Do you think it might be possible to include the IdentityConfig.cs file in the repository for both solutions? Without them, nothing makes any sense. Thanks!

    • Lund says:

      I am not sure I understand the question – IdentityConfig.cs is part of the repository, but there is only one solution.
      If you will clarify what you mean, I will try to help.

  2. MUHAMMED says:

    Hi can you help on same tutorials using web forms instead of MVC

  3. malik says:

    identityconfig.cs file is missing. Can you please fix? Thanks

    • Lund says:

      I seems I missed a commit – the project has been standing still a while now… I hope to continue during the next year or so…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s