Database 数据库设计-授予对记录的访问权限

Database 数据库设计-授予对记录的访问权限,database,database-design,Database,Database Design,我正在设计一个数据库,限制对某些对象的访问。我的同事和我讨论了不同的方法,主要的候选方法有:1)隐式访问和2)显式访问 为了进行说明,假设有以下表格: User (Id) ObjectA (Id, ParentId) -- Where ParentId is an ObjectA ObjectB (Id, ObjectAId) UserObjectA (UserId, ObjectAId) -- Grants access to an ObjectA UserObjectB (UserId, O

我正在设计一个数据库,限制对某些对象的访问。我的同事和我讨论了不同的方法,主要的候选方法有:1)隐式访问和2)显式访问

为了进行说明,假设有以下表格:

User (Id)
ObjectA (Id, ParentId) -- Where ParentId is an ObjectA
ObjectB (Id, ObjectAId)
UserObjectA (UserId, ObjectAId) -- Grants access to an ObjectA
UserObjectB (UserId, ObjectBId) -- Grants access to an ObjectB
隐式方法:

  • 由于ObjectA充当ObjectB的包含实体,因此,如果用户可以访问ObjectB的容器ObjectA,那么他也可以访问包含的ObjectB,即使UserObjectB中没有此类显式记录
  • 类似地,如果用户可以访问父ObjectA,则他可以访问所有ObjectA子体,即使UserObjectA中没有这样的记录
  • 此外,如果用户在两个访问授权表中都没有记录,则他可以隐式地访问ObjectA和ObjectB中的所有记录
  • 明确方法:

  • 要访问ObjectA或ObjectB记录,用户必须分别在UserObjectA或UserObjectB中拥有记录
  • 没有记录就等于没有访问权限,句号
  • 隐式方法有两个好处:1)当用户可以隐式访问多个对象时节省空间;2)隐式访问所有对象的用户可以访问将来添加的所有对象,而无需在创建对象时触发插入或在存储过程中处理插入

    显式方法的好处是查询更简单、可维护、性能更高

    最初,我们使用隐式方法。然而,在实现了各种存储过程之后,处理访问的逻辑变得非常复杂,我们遇到了各种微妙之处,使得这种方法比显式方法更容易出错。(请注意,实际场景比简化的示例要复杂一些。)我发现自己一直在实现递归CTE以确定访问,这不允许我(在考虑性能时)抽象视图或内联TVF中的某些逻辑部分。因此,我必须在许多不同的存储过程中重复和调整容易出错的逻辑。如果有任何变化,我们将有一个巨大的维护任务


    那么,我们使用这种隐式访问方法是否犯了错误?我肯定会三思而后行,希望有类似设计决策经验的人能给我一些建议。

    如果你能等一个月,Postgres 9.5将被淘汰,并具有路权安全性。如果你手头有一千万美元,甲骨文现在就有了

    目前,或在其他数据库中,您可以模拟行安全性:

  • 每个受保护的表都有一个“所有者”列。默认情况下,只有所有者可以选择、更新或删除该行

  • 每个“子”表还具有一个所有者列,该列具有到父表的级联外键。因此,如果更改parent.owner,那么也会更改所有的children.owner

  • 使用可更新的检查选项视图强制执行安全性

  • 您需要从应用程序中设置当前用户。对于pg+弹簧

  • 在研究生阶段:

    create schema protected;
    
    create table protected.foo (
      foo_id int primary key,
      bar text,
      owner name not null default_current user
    );
    
    create table protected.foo_children (
      foo_child_id int primary key,
      foo_id int not null references foo(food_id),
      owner name not null default current_user references foo(owner) on update cascade
    );
    
    现在一些检查选项视图-如果postgres:

    create view public.foo with (security_barrier) as 
      select
        *
      from protected.foo
      where
        owner = current_user
    WITH CHECK OPTION;
    
    create view public.foo_children with (security_barrier) as 
      select
        *
      from protected.foo_children
      where
        owner = current_user
    WITH CHECK OPTION;
    
    grant delete, insert, select, update on public.foo to some_users;
    grant delete, insert, select, update on public.foo_children to some_users;
    
    为了共享,您需要添加更多的表。重要的是,您可以为正确的列编制索引,这样就不会降低性能:

    create schema acl;
    
    create table acl.foo (
      foo_id int primary key references protected.foo(foo_id),
      grantee name not null,
      privilege char(1) not null
    );
    
    更新您的视图:

    create or update view public.foo with (security_barrier) as 
      select
        *
      from protected.foo
      where
        owner = current_user
        or exists ( select 1 from acl.foo where privilege in ('s','u','d') and grantee = current_user) );
    
     --add update trigger that checks for update privilege
    
     --add delete trigger that checks for delete privilege
    
    但我们每行需要不止一个“所有者”。UserObjectX表是多对多关系。FWIW,我正在使用SQL Server。