ASP.NET MVC 如何创建自定义角色提供程序

Posted

技术标签:

【中文标题】ASP.NET MVC 如何创建自定义角色提供程序【英文标题】:ASP.NET MVC How to create a custom role provider 【发布时间】:2017-06-15 21:43:43 【问题描述】:

对于 ASP MVC 来说相对较新,我不确定哪个更适合我的需求。我已经使用 Windows 身份验证构建了一个 Intranet 站点,并且我能够使用 Active Directory 角色来保护控制器和操作,例如

[Authorize(Roles="Administrators")]
[Authorize(Users="DOMAIN\User")]
public ActionResult SecureArea()

    ViewBag.Message = "This is a secure area.";
    return View();

我需要定义自己的安全角色,独立于 AD 角色。所需的功能是根据我的应用程序数据库中与他们的配置文件关联的一个或多个角色授予经过身份验证的用户访问特定操作的权限,例如:“经理”、“用户”、“访客”、“分析师”、“开发人员”等。

如何创建自定义角色提供者和/或自定义授权属性?

【问题讨论】:

我认为要求最好/最干净的方式会得到很多不同的答案。一个好的方法是自上而下。也就是说 - 在控制器级别授权,然后根据需要在方法/操作级别进行限制。您还可以实现一个区域基础控制器,然后该区域中的每个控制器都实现基础。如果未达到授权级别,区域基地控制器可以重定向到适当的页面。 【参考方案1】:

我的解决方案是创建一个自定义角色提供程序。以下是我采取的步骤,以防其他人以后需要帮助:

创建您的自定义用户和角色类

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
    
    

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
    
    

设置您的数据库上下文

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

创建您的角色提供者并实施以下方法

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

编辑您的 web.config 以设置数据库连接和角色提供程序参考

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

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

        ...
    

希望这对将来的某人有所帮助。祝你好运!

【讨论】:

【参考方案2】:

这篇文章对我帮助很大。 但是

var userRoles = userContext.Roles.Select(r => r.Name);

不获取当前用户角色,获取所有角色。

我想知道为什么每个人都可以访问大声笑。

【讨论】:

这是对原帖的回答,还是只是一般性评论?

以上是关于ASP.NET MVC 如何创建自定义角色提供程序的主要内容,如果未能解决你的问题,请参考以下文章

如何为 ASP.NET MVC 2 创建自定义成员资格提供程序?

在 ASP.Net 中使用自定义 RoleProvider 时如何允许多个角色查看页面

带有权限代码的 ASP.NET MVC 4 自定义授权属性(无角色)

在 asp.net mvc 5 中使用身份自定义用户和角色

Asp.net 身份 - 如何维护登录的用户角色?

ASP.NET 在使用 Windows 身份验证和自定义角色提供程序时实现“充当”功能