Responding to the heart of the matter, yes. It is possible.
Using Roles
The default ASP.NET MVC5 project configured with ASP.NET Identity does not have an already configured Role provider deployment, but this is fairly simple to set up:
Step 1: Create a ApplicationRoleManager
ApplicationRoleManager
is a Singleton that sets RoleManager
in your application. The RoleManager
is the ASP.NET Identity implementation for the Roles
scheme, very similar to the RoleProvider
of ASP.NET Membership.
There are several ways to do this. The one I did is implementing 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 this implementation someday, but it's for the 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 insert a user in Role :
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
var currentUser = userManager.FindByName(User.Identity.GetUserName());
var roleresult = userManager.AddToRole(currentUser.Id, "Nome da Role");
To verify that a user is in a Role , the command is the same as the ASP.NET Membership:
if (User.IsInRole("Padrão")) { ... }
The command can be used in Razor, in any View
Using Claims
I do not 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 validation policy before I can draw up a response (and I would therefore deserve a separate question).
In any case, here is an example of Claims implementation using as policy the zip code of the address of the user .
Addendum: Why can not I change the structure of tables
Within Models\IdentityModels.cs
of your project, we have the following class:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { ... }
IdentityDbContext
has the following implementation in its source code:
/// <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
, failing to use what is already standard. Not that it is impossible, but that for that you would have to reimplement the entire package, which I do not think is reasonable for a desired effect so small.