以编程方式向用户授予特定表权限的最佳方法?

Posted

技术标签:

【中文标题】以编程方式向用户授予特定表权限的最佳方法?【英文标题】: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。现在你该干杯了。”如果存在性能问题或其他问题,您可以通过添加更多资源等其他方式解决这些问题。 不过,我要说的是,如果您将每个角色中的用户成员身份存储为某个表中的一列,那是错误的方法。是否选中表单中的复选框应取决于用户现有的角色成员资格,而不是某些表中的某些标志。您实际上是通过存储实际的复选框值来对数据进行非规范化。根据所有角色的列表构建您的复选框列表,然后根据用户是否实际担任该角色来选中该框。 【参考方案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 件事来帮助解决性能问题:

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

权限表

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

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

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

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

【讨论】:

是的,我也在考虑使用 int 而不是 bool。我第二次没看懂,一栏权限是什么意思?是的,我可以消除权限表,但客户需要该表。

以上是关于以编程方式向用户授予特定表权限的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式授予本地用户权限以使用 .Net 启动服务

Android M:以编程方式撤销权限

Android M:以编程方式撤销权限

向 SQL Server 用户授予执行权限以仅运行特定作业

授予特定本地 Windows 用户组对文件夹及其子文件夹的读取权限

如何向组中的特定用户授予文件权限?