用于从数据库中检索基于角色的内容片段的选项

时间:2011-08-16 14:23:39

标签: c# sql sql-server web-services

我需要将一些基于角色的内容(产生一个对象的几个部分)从数据库带到服务层。对每个内容片段的访问将取决于用户具有的角色。如果用户角色无法访问某个片段,那么该片段将为空。这不是一个巨大的应用程序,只是一种基于角色公开某些内容的Web服务方法。

我可以用三种方式做到这一点。

1)根据用户角色,为每段内容进行数据库调用。

优点 - 角色在代码中进行管理,从而帮助业务逻辑(?)保留在代码中。只返回所需的数据。

缺点 - 多个数据库调用。添加新角色时需要修改代码。 (除非使用了一些非常复杂的业务逻辑。)

2)进行单个数据库调用并将所有内容片段作为单独的结果集返回。循环遍历集合并根据用户角色获取部分。

优点 - 单个数据库调用。角色在代码中进行管理。

缺点 - 需要为新角色修改代码。尽管可能不需要额外的数据。那些不必要的查询可能会增加几秒钟。

3)将角色发送到数据库并根据角色访问获取每个部分。

优点 - 单个数据库调用。只带回所需的东西。无需更改新角色的代码,因为只需要更改存储过程。

缺点 - 数据库中的业务逻辑?


在我看来#3> #2> #1。 (覆盖>意味着更好)

有没有人对哪种方法可能更好有任何见解?

更新 - 基于一些评论,下面会提供更多详情。

用户角色从另一个系统获得。理想情况下,#3会将其传递给db,并且粗略地将数据传递给db,返回数据,如果user_role =“admin”,则获取所有部分,“editor”获取内容部分1,3和55.再次,这是不是在db中完成角色管理的大型应用程序。它是一种Web服务方法,可以为几家公司提供一些数据。

我们显然无法使用此模型来管理应用程序中的角色。但是对于像这种情况中的方法级访问控制,我相信#3是最好的方法。由于角色来自另一个系统,而不是内容所在的系统,因此控制对不同内容片段的访问的逻辑必须驻留在某个地方。在这种特定情况下,数据库看起来像是一个可维护,可扩展,减少麻烦的解决方案的合适位置。也许,甚至在内容数据库中创建一个查找表来保存角色和内容片段访问权,以给出“数据”和“逻辑”分离的感觉,而不是拥有一个执行逻辑的udf。

如果没有人能想到针对#3的有效案件,我想我会继续这样做。

3 个答案:

答案 0 :(得分:1)

我总是选择选项3并在数据库中强制执行。

出于很多原因,最好在最接近实际数据的位置处理安全性。以这种方式看待它:以不同于抛出数据库模型的语言添加其他应用程序更为常见。发生这种情况时,您的所有角色处理代码都必须重复。

或者让我们说应用程序在黑客攻击期间被完全绕过。数据库仍然应该强制执行它的安全性。

最后,尽管人们喜欢将“业务逻辑”与他们的数据分开,但实际情况是,如果没有所述逻辑,大多数数据都没有意义。无论如何,进一步的“安全逻辑”与常规的“业务逻辑”不同。它是为了保护您和您的客户。但那是我的0.02美元。


看看你的其他选择:

2)您向客户端发送了太多数据。这既是安全又是性能,不是没有。如果您的应用不是发出数据请求的应用,该怎么办?如果您的应用中存在一个对用户显示过多的错误,该怎么办?

1和2)两者都需要重新部署甚至是轻微的逻辑变化(例如修复上面的神话错误)。这可能不是所希望的。就个人而言,我更喜欢对存储过程进行微调,而不是重新部署代码。在一个足够大的项目上,可能很难确切地知道所有部署的内容,并且通常具有更高的潜在问题。

<强>更新

根据您的其他信息,我仍然建议坚持使用#3。

答案 1 :(得分:1)

这取决于数据库的结构。

如果您可以管理数据库中的访问权限,则可能需要按照

的方式设置表格
Content Table
ContentId    Content   

Role Table
RoleID       RoleName

ContentAccess Table
ContentID    RoleID

然后将角色作为查询参数传递绝对不是“数据库中的业务逻辑”。您显然会编写一个查询来加入“content”和“contentaccess”表来检索内容表中的那些行,其中ContentAccess中有当前用户角色的匹配记录。

如果您的应用程序使用代码来确定是否允许用户查看特定内容,则不起作用。最粗略的例子是"if user_role = "admin" then get all content, if user_role = "editor" get items 1, 3 and 55“。我认为这不是一个可维护的设计 - 但你说应用程序开始时并不是那么大,所以它可能不是一个大问题。

理想情况下,我想重构应用程序以“将访问权限作为数据而非代码”进行管理,因为您确实将可维护性视为一项要求。

如果你不想那样做,那么选择1就是要走的路;您可以将其优化为“in”查询,而不是多个不同的查询。因此,您运行任何逻辑来确定用户角色是否可以看到内容,然后执行"select * from content where content_id in (1, 3, 55)"行的查询。

不同的人对存储过程有不同的感受;我的观点是避免使用存储过程,除非您有经过验证的,可衡量的性能要求,只能通过使用存储过程来满足。它们很难测试,难以调试,找到在Transact SQL和C#(或其他)方面都很出色的开发人员,以及版本控制等通常很痛苦。

答案 2 :(得分:0)

您预计每年会有多少新角色?如果角色很少,那么如果它使代码更简单,那么将所有内容都放在代码中。如果很多,请使用选项#3。

如果您真的不喜欢多次调用,您可以随时执行SELECT ... UNION或将检索推迟到简单的存储过程。

或者,考虑只获取无数RBAC框架之一并让它解决问题。