0

我最近一直在为数据库规范化和外键之间的关系在联结表和查找表方面摸不着头脑。

我目前有以下表格:Users、UserTypes、Roles、UsersInRoles 和 Permissions。UserTypes 只是一个查找表,通过 Users 表中的外键提供类型的名称和描述。角色是具有通过 UsersInRoles 表链接到每个用户的相关权限的各种角色。

我需要想出一个结构,允许我为每个用户提供多个角色,此外还为每个相应用户提供特殊权限,这些权限可能未包含在他们所属的固定角色中。

我从 Users 表中获得了我的 UsersInRoles 表的外键,但我认为它没有意义。相反,使用从 Users 表到 UserTypes 表的外键似乎很有意义。这是经验法则吗?联结表有外键链接到它所连接的表的主键,而主表有外键链接到关联查找表的主键?

参数:

  • 每个用户可以有一个或多个角色
  • 每个角色都有一组固定的权限
  • 每个用户都可以拥有其角色未提供的额外权限

我怀疑我可能还需要一个 PermissionsInRoles 联结表以及一个用于 PermissionsInUsers 的联结表?但这很荒谬不是吗?必须有更好的方法。我完全相信我在这里疯了,哈哈。任何帮助将不胜感激。这让我头晕目眩:P

更新
这基本上是如何设置的?我可能会去掉 UsersInRoles 表,这样每个用户只能担任一个角色,并且可以通过 SpecialPermissions 联结表添加其他权限。从 UI 的角度来看,我认为在向用户分配权限时可能会很好,选择“角色”只需选中与该角色关联的相应框,然后自定义并提交。这样我想我可能只需要用户表和权限表之间的连接表吗?啊。这对于第一次使用数据库的设计师来说是相当令人生畏的哈哈。还记得你刚开始的时候吗?或者,也许你们比我更天才,哈哈。

架构图片链接(还不能发布图片)

这是一篇关于查询驱动数据库设计的简洁学术文章(尽管已有 10 年历史),标题为:“针对不同查询模式的稳健数据库设计”。结论部分有一个有趣的方法。

4

3 回答 3

1

我怀疑我可能还需要一个 PermissionsInRoles 联结表以及一个用于 PermissionsInUsers 的联结表?

好吧,您已经说过其中一个要求是“每个角色都有一组固定的权限”。因此,要满足该要求,您需要存储适用于每个角色的权限。

Table: role_permissions
PK:    (Role, Permission)

Role    Permission
--
User    Create
User    Update
Admin   Create
Admin   Update
Admin   Delete

您不需要两个不同的表来实现该要求。

出于同样的原因,您已经说过“每个用户都可以拥有其角色未提供的额外权限”。要满足该要求,您必须存储特定于用户的权限。

Table: user_permissions
PK:    (username, permission)

username    permission
--
user1       Rename
user1       Leak to News of the World
user2       Randomly corrupt data

因此,同样,您不需要两个不同的表来实现该要求。这两个表都在 5NF 中。

但这很荒谬不是吗?

有什么可笑的?

  • 您对权限有非常详细的要求吗?
  • 您将业务数据(如权限)存储在表中吗?
  • 需要多个表来模拟您的权限要求?
  • 还有什么?

如果您需要有关实际表格的具体建议,请编辑您的问题并为您的表格插入 DDL。


之后

我看了你的图。不是每个表都需要一个 id 号;id 编号与规范化无关。

如果我正在设计您的系统,我可能不会在表 Roles、Permissions 和 UserTypes 中使用 id 编号,直到我看到 id 编号可以解决的性能问题。(在过去 30 年的大多数系统中,这意味着,嗯,几乎从来没有。)在我使用 id 号之前,我也会考虑使用人类可读的代码进行测试。人类可读的代码通常不需要连接;id 号码总是需要连接。

在大多数 SQL dbms 中,您可以在CREATE DOMAIN语句中组合数据类型和检查约束。在 PostgreSQL 中,您可能会使用类似的方法来减少表的数量。

CREATE DOMAIN role AS VARCHAR(7) NOT NULL
  CHECK (VALUE in ('Admin', 'User', 'Guest'));

其次是

CREATE TABLE user_roles (
  user_id integer not null references users (id),
  role_name role 
);

CREATE DOMAIN当行数稳定且相对较小时,用语句替换表最有用。就个人而言,我宁愿有桌子。

如果您坚持使用 id 编号,您还需要对 Roles.RoleName、Permissions.Description 和 UserTypes.UserType 进行 UNIQUE 约束。

否则,你似乎做得很好。

于 2011-07-12T11:10:42.127 回答
0

我以前做过的一件事,在类似的场景中:

将角色和用户保持在同一个表中。

有一个对象表(您将授予权限的表/查询/表单/等)

有一个权限表——这是您将角色/用户链接到对象的地方(即,John 可以在表 1 上选择)

最后,有一个继承表——这是您将角色/用户相互链接的地方(即,John 有权执行 Role1 可以执行的任何操作)

例如——这样的结构:

例如:

Users Table:
UserID -- User -- UserTypeID
1 ------- John Smith --- 1
2 ------- Sally Fort --- 1
3 ------- Public Role -- 2
4 ------- Special Role - 2

UserType Table:
UserTypeID -- Description
1 ----------- Human Being
2 ----------- Role

Objects Table:
1 -- Data-Entry Form 1
2 -- Data-Entry Form 2
3 -- Query 1
4 -- Table 1

Permissions Table
UserID -- ObjectID -- Permission
1      -- 1        -- Update (This says John can Update Data-Entry Form 1 (via direct permission))
3      -- 1        -- Update (This says that the Public Role can Update Data-Entry Form 1)
3      -- 2        -- Update (...as well as Data-Entry Form 2)
4      -- 3        -- Select (This says that the special role can Select from Query1)
4      -- 4        -- Insert (...the special role can Insert into Table1)

Permission Inheritance Table
UserID -- UserID_ToInheritFrom
1      -- 3 (this says John can do whatever the Public Role can do)
1      -- 4 (this says John can do whatever the Special Role can do)
2      -- 3 (this says Sally can do whatever the Public Role can do)

因此,如果您想查询“John 能做什么?”,您将执行以下操作:

SELECT
   ObjectID,
   Permission
FROM
   PermissionsTable
WHERE
   UserID = 1 -- John has direct permission
   OR UserID IN (SELECT UserID_ToInheritFrom FROM PermissionInheritanceTable WHERE UserID = 1)
   -- John has indirect permission via the Permission Inheritance Table (or you can call it the "role
   -- membership table" if that's easier for you to think of that way.)

这个实现效果很好。如果您想查看类似的实现,请查看 SQL-Server 的实现(或者更好的是,使用它,而不是从头开始重新创建轮子。)

于 2011-07-11T23:10:22.057 回答
0

如果您的安全对象只是一个产品表(或一组表),并且您使用的是 SSMS(SQL-Server Management Studio),那么您不应该从头开始发明自己的安全架构。

我建议您在 SSMS 中设置您的用户和角色——展开数据库,然后 --> 安全性 --> 用户等。右键单击用户,查找安全对象,然后您可以将用户分配给角色,或者也只是直接的对象(表等)。或右键单击角色,您有类似的选项。无论您做什么,都不要创建自己的安全架构,如果可以的话。

如果您需要您的网络应用程序能够访问数据库,请查看“实用帐户”(这些就像用户,在服务器级别而不是数据库级别创建,但是您可以从那里将它们带入您的数据库。) ; 或者,如果您能够在用户登录数据库时从内部网络传递用户的信用,请考虑模拟。实用帐户或用户可以分配给角色,或者授予对没有角色的数据库对象的直接访问权限——无论您需要什么。

于 2011-07-12T18:36:12.140 回答