【问题标题】:Best approach to give specific tables permissions programmatically to users?以编程方式向用户授予特定表权限的最佳方法?
【发布时间】:2017-05-31 14:14:24
【问题描述】:

我们有一个现有的工作系统,我被要求更改当前向用户授予“权限”的逻辑。当前的逻辑不是很合适,就性能而言,它太慢了。

当前结构

目前,我们有 25 个表,还有更多,我们有 110 个系统用户。有些是管理员,有些是具有特定权限的简单用户。我们在我们的系统中使用 M-V-C 实体框架代码优先方法。

对于每个表,我们有 5 个类似这样的复选框,第一个复选框用于授予访问页面的权限,第二个用于创建数据,第三个用于读取数据,第四个用于更新数据,第五个用于删除数据。

问题

现在所有这些权限都在一个用户表中,因此用户表中总共有 125 列。 25 个表格 x 5 个复选框 = 125 列。

所以,当我们注册用户时,我们可以选择权限,例如user1 只能从国家表中读取国家记录,只能从城市表中添加或编辑城市,只能从宗教表中删除宗教。

另外,系统有125个不同的角色。例如CountryCreateCountryDeleteCityCreateCityDelete 等等。

在用户注册过程中,系统根据选中的值将不同的角色关联到用户。因此,假设管理员想为用户提供 70 个权限,那么 70 个角色将与该特定用户相关联,并且由于用户众多,因此有数千个 UserRoles。如果用户具有特定角色,则创建角色以检查视图,然后显示特定功能,例如国家创建,否则不显示。

应用程序大部分时间都停止工作。因为每个用户都有很多角色和复选框。

我是该项目的新手,第一个工作是更改权限逻辑。实现它的最佳方法是什么?

当前代码

if (model.countryRead == true)
{
  var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
                    userManager.AddToRole(user.Id, "countryRead");
}

所以,像这样我们有 125 个if statements,它只用于注册。在编辑中,如果复选框为假,我们还有 else statements 从角色中删除。另外,我们在用户模型中有 125 个属性。

解决这个问题的最佳方法是什么?

【问题讨论】:

  • 您处理权限的方式没有任何问题。事实上,这就是您应该处理权限的方式。如果您的应用程序崩溃或出现问题,那是一个单独的不相关问题。代码不好或效率低下,服务器没有足够的资源,您的数据库需要调整等等。您将环境塑造成您的架构,而不是相反。
  • 所以你的意思是有 125 列和角色的表不是问题?
  • 定义“问题”。在你不得不放弃你的方法并重新开始之前,你可以拥有一些神奇的事物。您正在构建一个应用程序来满足您的业务。无论需要做什么,都需要这样做。从理论上讲,SQL 表中有 125 列之类的东西并没有固有的问题。这不像 SQL Server 会说“不,我只支持 124。现在你该干杯了。”如果存在性能问题或其他问题,您可以通过添加更多资源等其他方式解决这些问题。
  • 不过,我要说的是,如果您将每个角色中的用户成员身份存储为某个表中的一列,那是错误的方法。是否选中表单中的复选框应取决于用户现有的角色成员资格,而不是某些表中的某些标志。您实际上是通过存储实际的复选框值来对数据进行非规范化。根据所有角色的列表构建您的复选框列表,然后根据用户是否实际担任该角色来选中该框。

标签: asp.net-mvc entity-framework ef-code-first user-permissions


【解决方案1】:

你可以按照这个方法:

您已经拥有UserRole 模型。你只需要另一个具有这种结构的模型:

public enum Actions
{
    Insert,
    Delete,
    Update,
    GetOne,
    GetAll
}

public enum Services
{
    Country,
    Category,
    Product,
    Warehouse
}

public class UserAccess
{
    public int Id { get; set; }
    public ApplicationRole Role { get; set; }
    public string Title { get; set; }
    public Actions Action { get; set; }
    public Services Service { get; set; }
}

使用此模型,您可以定义无限访问。 UsersRoles 每个Role 可以有很多UserAccess

之后,你必须像125 if statements一样手动检查它或者做一个更好的方法,如果你使用Web API,我建议你:

首先,您必须从 AuthorizeAttribute 类继承并使用您的访问模型(例如 UsersRolesUserAccesses)对其进行自定义,并且您还必须覆盖 OnAuthorization 方法,例如:

public class ServiceAuthorize : AuthorizeAttribute
    {
        public ServiceAuthorize(Actions action, params Services[] services)
        {
            this.action = action;
            this.services = services.ToList();
        }
        private Actions action { get; set; }
        private List<Services> services { get; set; }
        public override void OnAuthorization(HttpActionContext actionContext)
        {
              // check the user's roles here
              // if the user don't have needed role or access you can reject it with this code
             if (Unauthorized)
             {
                 actionContext.Response = actionContext.Request.CreateResponse(
                                    HttpStatusCode.Unauthorized,
                                    new Dictionary<string, string> {
                                                { HttpStatusCode.Unauthorized.ToString(), ((int)HttpStatusCode.Unauthorized).ToString() }
                                   }
                   );
             } 
        }
    } 

那么,您必须在您的 Web API 中像这样使用ControllersActions 上方的这个属性:

 public class CountryController : ApiController
    {
        [ServiceAuthorize(new List<Actions>() { Actions.GetAll }, new List<Services>() { Services.Country })]
        public string GetCountries()
        {

        }

        [ServiceAuthorize(new List<Actions>() { Actions.Insert }, new List<Services>() { Services.Country })]
         public string AddCountry(Country country)
         {

         }
    }

希望对你有所帮助。

【讨论】:

    【解决方案2】:

    在不了解您的项目结构(或瓶颈实际在哪里)的情况下很难给出建议,但您至少可以做 5 件事来帮助解决性能问题:

    1. 不要使用 5 个boolean 字段作为权限,而是使用单个按位int 字段,并将值转换为 UI 上的 5 个复选框。例如1=access;2=create;4=read;8=update;16=delete,那么如果该字段的值为13,则用户将具有访问、读取和更新的权限(1+4+8=13)。
    2. 不清楚为什么每个表都有一列。为每个表设置一行会更有意义,然后您可以为权限设置一列。
    3. 同时拥有“复选框”和“角色”听起来有点矫枉过正。如果您的每个角色都是一个权限,您可以完全消除“权限”表。
    4. 您可以通过使用System.Runtime.Caching.MemoryCache 在内存中缓存权限(和/或角色)来显着提高性能。
    5. 确保您的角色/权限未保存在 cookie 中,因为这意味着 每个 HTTP 请求无论是页面、图像、CSS 文件等,都会往返发送 cookie,这可以翻译大量额外字节的网络流量。

    权限表

    不确定客户“想要桌子”的原因。也许他们想要数据(已经作为角色存在),这就是您解释它的方式。您的首选应该是消除数据重复并仅使用角色(因为角色很容易被 MVC 使用)。

    如果不可能,那么这就是你可以做的事情

    UserID | Table (string)           | Permission (int)
    ---------------------------------------------------
    1      | Table1                   | 13
    1      | Table2                   | 17
    2      | Table5                   | 3
    

    请记住,控制“权限”的是您的应用程序,而不是实际存储数据的方式。但是可维护的数据库只会将数据存储在一个地方,让应用程序处理如何使用、显示和更新数据。

    【讨论】:

    • 是的,我也在考虑使用 int 而不是 bool。我第二次没看懂,一栏权限是什么意思?是的,我可以消除权限表,但客户需要该表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-09
    • 2014-03-15
    • 2018-01-18
    • 2018-11-08
    • 1970-01-01
    • 2018-07-22
    • 2015-09-22
    相关资源
    最近更新 更多