Answering the point, yes. It’s possible.
Using Roles
The standard ASP.NET MVC5 project configured with ASP.NET Identity does not bring an ASP.NET Identity provider implementation Roll already configured, but this is quite simple to configure:
Step 1: Create a ApplicationRoleManager
The ApplicationRoleManager
is a Singleton who sets up the RoleManager
in its application. The RoleManager
is the ASP.NET Identity implementation for the Roles
, very similar to the RoleProvider
of ASP.NET Membership.
There are several ways to do this. What I’ve done is to implement the class within App_Start/IdentityConfig.cs
:
public class ApplicationRoleManager : RoleManager<IdentityRole, string>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(new RoleStore<IdentityRole>(new ApplicationDbContext()));
}
}
(I intend to improve that implementation some day, but it serves to answer for now).
Step 2: Create a CRUD for Roles
Controllers/Rolescontroller.Cs
namespace SeuProjeto.Controllers
{
public class RolesController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
private readonly ApplicationRoleManager _roleManager = new ApplicationRoleManager(new RoleStore<IdentityRole>(db));
// GET: Roles
public ActionResult Index()
{
var roles = _roleManager.Roles.ToList();
return View(roles);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public async Task<ActionResult> Create(IdentityRole role)
{
if (ModelState.IsValid)
{
await _roleManager.CreateAsync(role);
return RedirectToAction("Index");
}
return View(role);
}
public ActionResult Edit(Guid id)
{
var role = _roleManager.Roles.SingleOrDefault(r => r.Id == id.ToString());
return View(role);
}
[HttpPost]
public async Task<ActionResult> Edit(IdentityRole role)
{
if (ModelState.IsValid)
{
await _roleManager.UpdateAsync(role);
return RedirectToAction("Index");
}
return View(role);
}
// GET: Roles/Delete/5
public ActionResult Delete(Guid? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var role = _roleManager.Roles.SingleOrDefault(r => r.Id == id.ToString());
if (role == null)
{
return HttpNotFound();
}
return View(role);
}
// POST: Roles/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(Guid id)
{
var role = await _roleManager.Roles.SingleOrDefaultAsync(r => r.Id == id.ToString());
_roleManager.Delete(role);
return RedirectToAction("Index");
}
}
}
Views/Index.cshtml
@model IEnumerable<Microsoft.AspNet.Identity.EntityFramework.IdentityRole>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Users</th>
</tr>
</thead>
<tbody>
@foreach (var role in Model)
{
<tr>
<td>@role.Id</td>
<td>@role.Name</td>
<td>
@role.Users.Count
</td>
</tr>
}
</tbody>
</table>
Views/Create.cshtml
@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
@using (Html.BeginForm())
{
@Html.LabelFor(model => model.Name)
@Html.EditorFor(model => model.Name)
<button type="submit">Enviar</button>
}
Views/Edit.cshtml
@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
@using (Html.BeginForm())
{
@Html.HiddenFor(model => model.Id)
@Html.LabelFor(model => model.Name)
@Html.EditorFor(model => model.Name)
<button type="submit">Enviar</button>
}
Views/Delete.cshtml
@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Color</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Name)
</dd>
</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>
To enter a user in Roll:
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
var currentUser = userManager.FindByName(User.Identity.GetUserName());
var roleresult = userManager.AddToRole(currentUser.Id, "Nome da Role");
To check if a user is on Roll, the command is the same as ASP.NET Membership:
if (User.IsInRole("Padrão")) { ... }
The command can be used in Razor, in any View
Using Claims
I don’t know if it’s worth describing the whole process because Claims
is based on the concept of validation policies. It would be necessary to define a policy of validation beforehand so that I could draft an answer (and therefore deserve a separate question).
In any case, here is an example of implementing Claims using as policy the user address ZIP code.
Addendum: Why it is not possible to change the table structure
Within Models\IdentityModels.cs
of your project, we have the following class:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { ... }
IdentityDbContext
has in its source code the following implementation:
/// <summary>
/// Maps table names, and sets up relationships between the various user entities
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (modelBuilder == null)
{
throw new ArgumentNullException("modelBuilder");
}
// Needed to ensure subclasses share the same table
var user = modelBuilder.Entity<TUser>()
.ToTable("AspNetUsers");
user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
user.Property(u => u.UserName)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") {IsUnique = true}));
// CONSIDER: u.Email is Required if set on options?
user.Property(u => u.Email).HasMaxLength(256);
modelBuilder.Entity<TUserRole>()
.HasKey(r => new {r.UserId, r.RoleId})
.ToTable("AspNetUserRoles");
modelBuilder.Entity<TUserLogin>()
.HasKey(l => new {l.LoginProvider, l.ProviderKey, l.UserId})
.ToTable("AspNetUserLogins");
modelBuilder.Entity<TUserClaim>()
.ToTable("AspNetUserClaims");
var role = modelBuilder.Entity<TRole>()
.ToTable("AspNetRoles");
role.Property(r => r.Name)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") {IsUnique = true}));
role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
}
To avoid constructing these tables, you would have to rewrite IdentityDbContext
, not using what is already standard. Not that it is impossible, but that for this you would have to reimplementate the whole package, which I do not think reasonable for a desired effect so small.
Here I come. This is gonna be big.
– Leonel Sanches da Silva