我正在为真实世界组织的成员在Rails中构建一个基于社区的站点。我正在努力坚持RESTful设计的最佳实践,而且大多数都是或多或少地通过书本。使我的大脑在整洁的RESTful圈子中运行的问题是授权。 身份验证是一个容易,长期解决的问题,广泛接受的RESTful解决方案,但RESTful授权似乎有点黑色艺术。我正在尝试找到这样一种方法,它将提供最通用和灵活的框架来控制对资源的访问,同时尽可能简单,同时符合RESTful架构。 (还有一匹小马。)

考虑:

  1. 我需要控制对各种资源的访问,例如用户,页面,帖子等等。
  2. 给定资源的授权必须比简单的CRUD更精细。
  3. 我希望允许自己和他人在应用程序中编辑授权规则。
  4. 应允许授权规则依赖于谓词,例如(概念上)所有者(用户,资源)或锁定(主题)
  5. 考虑(2)是我最关心的问题。在我的权限概念和RESTful动作概念之间似乎存在阻抗不匹配。例如,选择帖子(如留言板)。 REST指示在Post资源上存在四个操作:创建,读取,更新和删除。很容易说用户应该能够更新自己的帖子,但只允许某些用户(或角色或组)锁定它们。表示锁定的传统方式是在Post的状态内,但这导致了在相同条件下的用户可能或可能无法根据他提供的(完全有效)值更新帖子的气味。我似乎很清楚,改变邮政状态确实有两种不同的行动,而对它们进行偷窃只是为了掩饰违反REST原则的行为。

    (我应该注意,这个问题与由于无效或不一致的数据而导致更新失败的问题截然不同而且#nid;来自非特权用户的锁定请求原则上非常有效,只是禁止。)

      

    不会分解另一个词腐烂吗?

    这可以通过分解帖子来克服:一个锁是特定帖子的子资源,而创建或销毁一个可能具有单独的权限。这个解决方案具有REST环,但它带来了理论和实践方面的困难。如果我将锁定分解出来,那么其他属性呢?假设我完全决定只允许一名管理员修改帖子的标题?然后,授权的简单更改需要重组数据库以适应它!这不是一个解决方案。为了在分解策略下允许这种灵活性,需要每个属性都是资源。这有点进退两难。我的隐含假设是资源在数据库中表示为表。在此假设下,每个属性的资源表示每个属性的表。显然,这是不切实际的。但是,要消除这种假设会导致表和资源之间的阻抗不匹配,这可能会打开它自己的蠕虫病毒。使用这种方法需要比我给出的更深入的考虑。一方面,用户合理地希望能够一次编辑多个属性。请求在哪里?到包含所有属性的最小资源?并行地对每个单独的资源?到了月球?

      

    其中一些事情与其他事情不同,

    假设我没有分解贡品。然后,替代方案似乎是为每个资源定义一组权限。然而,在这一点上,REST的同质性已经丧失。为了定义资源的访问规则,系统必须具有该资源功能的特定知识。此外,现在不可能一般地将权限传播给后代资源—即使子资源具有相同名称的特权,特权之间也没有固有的语义连接。在我看来,定义一组类似REST的标准权限是两个世界中最糟糕的,所以我对每种类型的资源都有一个单独的权限层次结构。

      

    嗯,我们做了鼻子。还有帽子。但这是一种资源!

    我看到的一个建议减轻了上述方法的一些缺点,即将权限定义为资源上的创建/删除和属性上的读/写。该系统是属性 - 资源和每资源特权之间的折衷:一个仍然只有CRUD,但为了授权,读取和更新属于属性,可以将其视为伪资源。这提供了属性 - 资源方法的许多实际好处,尽管概念完整性在某种程度上受到了损害。权限仍然可以从资源传播到资源,从资源传播到伪资源,但绝不会从伪资源传播。我还没有充分探讨这一战略的后果,但似乎它似乎很有希望。在我看来,这样的系统最适合作为模型的组成部分。例如,在Rails中,它可能是 ActiveRecord 的改进。这对我来说似乎相当激烈,但授权是一个基本的交叉问题,这可能是合理的。

      

    哦,不要忘记小马

    所有这些都忽略了预测权限的问题。显然,用户应该能够编辑自己的帖子,但没有其他人的帖子。同样显然,管理员编写的权限表不应该为每个用户分别记录。这几乎不是一个罕见的要求—诀窍是使它成为通用的。我认为只需要使规则具有预测性就可以获得我需要的所有功能,这样就可以快速,立即地确定规则的适用性。规则“允许用户写帖子作者(用户,帖子)"将转换为所有用户的“,发布以使作者(用户,帖子),允许用户写帖子”和“拒绝所有写帖子锁定(帖子)"到“ for all Post,以便Locked(Post),拒绝所有写帖子”。 (如果所有这样的谓词都可以用一个用户和一个资源来表达,那么它将是 grand 。)概念上得到的“最终”和“最终”。规则将是非预测性的。这提出了如何实现这样一个系统的问题。谓词应该是Model类的成员,但我不确定如何在规则的上下文中优雅地引用它们。要安全地这样做需要某种反思。在这里我再次感觉这将需要改进模型实现。

      

    你怎么拼写那个?

    最后一个问题是如何最好地将这些授权规则表示为数据。数据库表可能有这个技巧,enum列为allow / deny和C / R / U / D(或者可能是CRUD位?或者可能是{C,R,U,D}× {allow,deny,inherit }?),以及带路径的资源列。或许,为方便起见,“继承”位。就谓词而言,我很茫然。单独的桌子?当然有很多缓存来阻止它 t

有帮助吗?

解决方案

抱歉,我没有时间做正义的这个问题,但很高兴看到一些经过深思熟虑的问题。 以下是一些评论:

不要陷入将HTTP谓词映射到CRUD的陷阱。是GET和DELETE映射非常干净,但PUT可以执行创建和更新(但仅完全替换),POST是通配符动词。 POST实际上是处理不适合GET,PUT和 删除。

使用属性来表示对象的状态只是一种状态管理方法。我猜您可以想象以下请求可能会做什么:

POST /LockedPosts?url=/Post/2010

子资源也是管理资源当前状态的有效方法。我不觉得有必要对待资源的“状态”。属性及其“数据”属性一致。

尝试将资源直接映射到表格会严重限制您。不要忘记,当您遵循REST约束时,您可以使用的动词突然非常有限。您需要能够在您使用的资源中创造性地弥补这一点。将自己限制为一个资源等于一个表将严重限制最终应用程序的功能。

我们经常看到Rails,ASP.NET MVC和WCF Rest用户在StackOverflow上发布关于如何在REST约束下做某些事情的问题。问题通常不是REST的约束,而是框架在支持RESTful应用程序方面的局限性。我认为首先找到问题的RESTful解决方案然后看看是否可以将其映射回您选择的框架是至关重要的。

创建一个存在于比资源本身更细粒度的权限模型。请记住,其中一个关键的REST约束是超媒体。超媒体不仅可用于查找相关实体,还可用于表示有效/允许的状态转换。如果返回包含嵌入式链接的表示,有条件地基于权限,则可以控制谁可以执行哪些操作。即如果用户有权解锁POST 342,那么您可以返回表示中嵌入的以下链接:

<Link href="/UnlockedPosts?url=/Post/342" method="POST"/>

如果他们没有该权限,则不要返回该链接。

我认为你在这里遇到的一个困难就是你想要立刻咀嚼太大的问题。我认为您需要查看您尝试向客户端公开的RESTful接口,作为管理权限和谓词的一个明显问题,以便管理域模型中的授权。

我意识到我没有直接回答你的任何问题,但希望我提供了一些可能在某种程度上有所帮助的观点。

其他提示

我最近发现了一种认证解决方案,似乎解决了我的大多数问题。如果你最喜欢这个问题,那么你可能会感兴趣:

https://github.com/stffn/declarative_authorization

正如Darrel指出的那样 - REST不是CRUD。如果您发现已识别的资源过于粗糙,以至于统一接口无法提供足够的控制,则将资源拆分为子资源,并将原始资源用作其组件超链接的“集合”。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top