ASP.NET MVC How to Create a Custom Role Provider

Being relatively new to ASP MVC, I'm not sure what works best for my needs. I created an intranet site using Windows Authentication, and I can protect controllers and actions using Active Directory roles, for example.

[Authorize(Roles="Administrators")]
[Authorize(Users="DOMAIN\User")]
public ActionResult SecureArea()
{
    ViewBag.Message = "This is a secure area.";
    return View();
}

I need to define my own security roles regardless of AD roles. The desired functionality is that authenticated users are granted access to certain actions in accordance with one or more roles associated with their profile in my application database, for example: “Manager”, “User”, “Guest”, “Analyst” , "Developer", etc.

How to create a custom role provider and / or custom authorization attribute?

EDIT: edited title and question so that other users can identify the content of the message.

+6
source share
1 answer

My solution was to create a personalized role provider. Here are the steps I took if someone else needed help later:

Create your own custom classes and role classes

using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Security.Models.Security
{
    public class AppRole : IdentityRole
    {
    }
}

and

using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Security.Models.Security
{
    public class AppUser : IdentityUser
    {
    }
}

Setting up a database context

using Microsoft.AspNet.Identity.EntityFramework;
using Security.Models.Security;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace Security.Models.DAL
{
    public class UserContext : IdentityDbContext<AppUser>
    {
        public UserContext() : base("UserContext")
        {
            Database.SetInitializer<UserContext>(new CreateDatabaseIfNotExists<UserContext>());
        }
    }
}

Create a role provider and complete the following methods

using Security.Models.DAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;

namespace Security.Models.Security
{
    public class AppRoleProvider : RoleProvider
    {
        public override string[] GetAllRoles()
        {
            using (var userContext = new UserContext())
            {
                return userContext.Roles.Select(r => r.Name).ToArray();
            }
        }

        public override string[] GetRolesForUser(string username)
        {
            using (var userContext = new UserContext())
            {
                var user = userContext.Users.SingleOrDefault(u => u.UserName == username);
                var userRoles = userContext.Roles.Select(r => r.Name);

                if (user == null)
                    return new string[] { };
                return user.Roles == null ? new string[] { } :
                    userRoles.ToArray();
            }
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            using (var userContext = new UserContext())
            {
                var user = userContext.Users.SingleOrDefault(u => u.UserName == username);
                var userRoles = userContext.Roles.Select(r => r.Name);

                if (user == null)
                    return false;
                return user.Roles != null &&
                    userRoles.Any(r => r == roleName);
            }
        }
    }
}

Edit the web.config file to configure the link to the database connection and the role of the link provider

<connectionStrings>
    <add name="UserContext" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\UserContext.mdf;Initial Catalog=UserContext;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>

and

<system.web>
    ...
    <authentication mode="Windows" />        
    <roleManager enabled="true" defaultProvider="AppRoleProvider">
      <providers>
        <clear/>
        <add name="AppRoleProvider" type="Security.Models.Security.AppRoleProvider" connectionStringName = "UserContext"/>
      </providers>
      ...
    </roleManager>
  </system.web>

enable-migrations

Configurations.cs / , '\'

namespace Security.Migrations
{
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.EntityFramework;
    using Security.Models.Security;
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<Security.Models.DAL.UserContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            ContextKey = "Security.Models.DAL.UserContext";
        }

        protected override void Seed(Security.Models.DAL.UserContext db)
        {
            // Set up the role store and the role manager
            var roleStore = new RoleStore<AppRole>(db);
            var roleManager = new RoleManager<AppRole>(roleStore);

            // Set up the user store and the user mananger
            var userStore = new UserStore<AppUser>(db);
            var userManager = new UserManager<AppUser>(userStore);

            // Ensure that the user manager is able to accept special characters for userNames (e.g. '\' in the 'DOMAIN\username')            
            userManager.UserValidator = new UserValidator<AppUser>(userManager) { AllowOnlyAlphanumericUserNames = false };

            // Seed the database with the administrator role if it does not already exist
            if (!db.Roles.Any(r => r.Name == "Administrator"))
            {
                var role = new AppRole { Name = "Administrator" };
                roleManager.Create(role);
            }

            // Seed the database with the administrator user if it does not already exist
            if (!db.Users.Any(u => u.UserName == @"DOMAIN\admin"))
            {
                var user = new AppUser { UserName = @"DOMAIN\admin" };
                userManager.Create(user);
                // Assign the administrator role to this user
                userManager.AddToRole(user.Id, "Administrator");
            }
        }
    }
}

,

update-database

,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Security.Models.Security
{
    public class AccessDeniedAuthorizationAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);

            if(filterContext.Result is HttpUnauthorizedResult)
            {
                filterContext.Result = new RedirectResult("~/Home/AccessDenied");
            }
        }
    }
}

! ( ~/Home/AccessDenied) ,

using Security.Models.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Security.Controllers
{
    public class HomeController : Controller
    {
         ...    

        [AccessDeniedAuthorizationAttribute(Roles = "Administrator")]
        public ActionResult SecureArea()
        {
            return View();
        }

        public ActionResult AccessDenied()
        {
            return View();
        }

        ...
    }
}

, - . !

+8

Source: https://habr.com/ru/post/1014559/


All Articles