Asp.Net Identity, how to use only Roles or Claims?

Asked

Viewed 6,255 times

19

Returning to the same subject: ASP.NET Identity with Entityframework.

Regardless of the size or planning of my project, if I need to use only the part of Roles or only the part of Claims, Is that possible? And most of all, how?

Finally, inhibit the properties and methods related to one or the other and do not create the tables in the database related to what was unused.

1 answer

22


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.

  • 2

    I was going to authenticate via Claims, but as I have many items, I did a test with 300claims, it got lost and did not load in memory :, I opted for scrolling even

  • I went a little further in that answer, but I need more time. It’s complicated my day-to-day here.

  • 2

    @Tiagosilva of course! http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.EntityFramework/2.0.0-beta1-140128/Release/Default/Microsoft.AspNet.Identity.EntityFramework

Browser other questions tagged

You are not signed in. Login or sign up in order to post.