ASP.NET MVC How to create a custom role provider

后端 未结 1 1944
臣服心动
臣服心动 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
        {
            public UserContext() : base("UserContext")
            {
                Database.SetInitializer(new CreateDatabaseIfNotExists());
            }
        }
    }
    

    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

    
        
    
    

    and

    
        ...
                
        
          
            
            
          
          ...
        
      
    

    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
        {
            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(db);
                var roleManager = new RoleManager(roleStore);
    
                // Set up the user store and the user mananger
                var userStore = new UserStore(db);
                var userManager = new UserManager(userStore);
    
                // Ensure that the user manager is able to accept special characters for userNames (e.g. '\' in the 'DOMAIN\username')            
                userManager.UserValidator = new UserValidator(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)
提交回复
热议问题