ASP.NET MVC How to create a custom role provider

后端 未结 1 1926
臣服心动
臣服心动 2020-12-08 05:40

Being relatively new to ASP MVC, I\'m unsure which would better suit my needs. I have built an intranet site using Windows authentication and I\'m able to secure controllers

相关标签:
1条回答
  • 2020-12-08 06:21

    My solution was to create a custom role provider. Here are the steps I took, in case anyone else needs help later:

    Create your custom user 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
        {
        }
    }
    

    Set up your 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 your role provider and implement 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 your web.config to set up the database connection and role provider reference

    <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>
    

    In package manager console, enable migrations

    enable-migrations
    

    In the newly created Configurations.cs set up the user/role stores and managers and configure the user manager validator to accept '\' characters

    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");
                }
            }
        }
    }
    

    In package manager console, ensure the database is created and seeded

    update-database
    

    Create a custom authorization attribute that will redirect to an access denied page on failure

    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");
                }
            }
        }
    }
    

    You're done! You can now create an access denied page (in this case ~/Home/AccessDenied) and apply the attribute to any action, e.g.

    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();
            }
    
            ...
        }
    }
    

    Hope this helps someone in the future. Good luck!

    0 讨论(0)
提交回复
热议问题