问题 是否有通过RESTful API将资源权限/ ACL暴露给前端的最佳实践?


问题几乎涵盖了它。给定一个RESTful API,我们有多种资源类型和围绕谁可以CRUD的各种用户权限,是否有任何已建立的最佳实践将这些权限暴露给前端,以便权限不必存储在两个位置?

我有一个纯JS应用程序,我需要知道何时,例如,显示编辑和删除给定资源的链接。我想要一种标准的方法来直接根据存储在后端的ACL做出这些决定。我考虑过可能会在REST信封中为所有GET响应带回ACL部分,但我希望也许有人知道已建立的最佳实践。

对于它的价值,我也使用Symfony2及其安全组件。


3217
2017-10-20 23:47


起源



答案:


在纯RESTful场景中,客户端根本不管理ACL。相反,当客户端请求信息时,返回的资源将包括从这些资源到客户端可能遵循的可能链接的链接。这样,服务器就会告诉客户端使用给定资源可以做什么和不能做什么(特定于谁请求它)。

示例:您的JS客户端检索已购买但尚未发货的商品的JSON有效负载。客户端可能会收到如下所示的有效负载:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "ORDERED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET"),
    "cancel-shipment": {  "href": "/item/a631723d69",
                 "method": "DELETE" }
  }
}

由于服务器返回了取消 - 发货链接关系,这意味着允许取消订单中的项目 目前。但想象一下资源在发货后可能会是什么样子,并在几天后提出请求:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "SHIPPED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET")
  }
}

取消 - 发货链接关系将不再从服务器返回,因为它不再是允许的操作(即,在发货后您无法取消订单)。

可以以相同的方式管理更传统的访问控制(即,不将取消 - 发货链接发送给未授权的用户)。假设订单尚未发货,您的配偶可以看到您订购的是什么,但不允许取消订单。他们得到了回报:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "ORDERED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET")
  }
}

总而言之,每个响应中返回的链接封装并表示请求者在系统中的任何给定时刻被授权执行的操作。

无论如何,你 必须 检查服务器上是否有适当的授权请求,因为您永远不知道有人可能正在使用原始URL进行攻击。


12
2017-10-21 01:17



啊,这是一个很好的观点。我没有考虑过将客户策略仅仅基于返回的链接。事后来看这很明显..谢谢! - Jason McClellan
@Jonathan W:同样,您认为根据授权用户的权限修改Order对象的实际结构是否有效?例如,如果我的妻子可以看到我订购的东西,但是我不应该看到我付了多少钱,您认为在没有价格属性的情况下退回订单对象是否有效? - MajorRefactoring
你对“Order对象的实际结构”是什么意思?您的意思是根据您的身份返回订单资源的不同表示形式吗?你可以这样做,但请记住,这会破坏你有效缓存资源的能力。 (而且,正如我所指出的那样,我对这个问题的回答也是如此。) - Jonathan W


答案:


在纯RESTful场景中,客户端根本不管理ACL。相反,当客户端请求信息时,返回的资源将包括从这些资源到客户端可能遵循的可能链接的链接。这样,服务器就会告诉客户端使用给定资源可以做什么和不能做什么(特定于谁请求它)。

示例:您的JS客户端检索已购买但尚未发货的商品的JSON有效负载。客户端可能会收到如下所示的有效负载:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "ORDERED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET"),
    "cancel-shipment": {  "href": "/item/a631723d69",
                 "method": "DELETE" }
  }
}

由于服务器返回了取消 - 发货链接关系,这意味着允许取消订单中的项目 目前。但想象一下资源在发货后可能会是什么样子,并在几天后提出请求:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "SHIPPED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET")
  }
}

取消 - 发货链接关系将不再从服务器返回,因为它不再是允许的操作(即,在发货后您无法取消订单)。

可以以相同的方式管理更传统的访问控制(即,不将取消 - 发货链接发送给未授权的用户)。假设订单尚未发货,您的配偶可以看到您订购的是什么,但不允许取消订单。他们得到了回报:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "ORDERED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET")
  }
}

总而言之,每个响应中返回的链接封装并表示请求者在系统中的任何给定时刻被授权执行的操作。

无论如何,你 必须 检查服务器上是否有适当的授权请求,因为您永远不知道有人可能正在使用原始URL进行攻击。


12
2017-10-21 01:17



啊,这是一个很好的观点。我没有考虑过将客户策略仅仅基于返回的链接。事后来看这很明显..谢谢! - Jason McClellan
@Jonathan W:同样,您认为根据授权用户的权限修改Order对象的实际结构是否有效?例如,如果我的妻子可以看到我订购的东西,但是我不应该看到我付了多少钱,您认为在没有价格属性的情况下退回订单对象是否有效? - MajorRefactoring
你对“Order对象的实际结构”是什么意思?您的意思是根据您的身份返回订单资源的不同表示形式吗?你可以这样做,但请记住,这会破坏你有效缓存资源的能力。 (而且,正如我所指出的那样,我对这个问题的回答也是如此。) - Jonathan W