GraphQL业务层中的列表和分页授权

问题描述:

在Dan Schafer的优秀"GraphQL at Facebook" talk from React Europe中,他介绍了如何在业务层模型中集中授权以避免必须为通向授权节点的每条边重复授权逻辑的问题。GraphQL业务层中的列表和分页授权

Three layer

这工作得很好类似​​这在我的情况下,最终结束了查询数据库为SELECT * from todos WHERE id=1,然后验证与checkCanSee(resultFromDatabase)授权。

但是,比方说我的todos表现在包含来自多个用户的100,000个todos,纯粹在业务层执行授权变得不切实际,因为我需要获取每个待办事项,使用共享授权逻辑过滤结果,然后切片执行分页。

我错了,认为解决这个问题的唯一方法是让授权逻辑驻留在持久层本身?

我认为Dan的演讲中的一个要点是授权与GraphQL处理方式的区别,而不是典型的REST端点。

在REST中,每个资源通常都与单个端点相关联。当向该端点发出请求时,在处理请求之前检查请求者是否被授权是有意义的。使用GraphQL我们可能会在同一个请求中获取多个资源,所以这种行为不再需要。正如丹所说:

如果您看不到[请求的资源]之一,我们不想完全放弃请求。

因此,与GraphQL首选的方法是实现某种每个节点机制的授权,并只返回请求者有权查看的资源。这正是谈话中的例子 - 这是一种方式。

如果您保存您的待办事项在SQL数据库中的表,就可以完美地为您的代码,只是做一个查询像SELECT * from todos WHERE creator_id=${viewer.id}和使用功能就像checkCanSee完全忽略。

同样,你可以将分页权利用限制偏移,游标等进行查询,并且是的,因为你现在让你的数据库完成繁重的工作,你可以说我们已经进入了持久化层。但是,接受请求,清理输入,构造适当的查询并返回GraphQL可以使用的表单的结果仍然取决于业务逻辑。

我不能为丹说话,但我想他的意图不是建议这是实现节点授权的唯一(甚至最佳)方式。我觉得更重要的一点是,如果你有,例如,取:

{ 
    header 
    todos { 
    description 
    } 
    quoteOfTheDay 
} 

即使未授权客户端还是应该得到响应从服务器,它可以再用来呈现为最终用户页面(即使该响应包含一个空的待办事项数组)。

+0

我仍然坚信让授权逻辑驻留在存储层是不理想的。当你的缓存后面进行授权时,你会如何在业务逻辑和存储层之间实现缓存?另外,如果我决定在某些字段中使用SQL连接器,而在其他字段中使用另一个后端系统,该怎么办?我必须为后台系统实施授权。 –

+0

GraphQL的目的是要有一个“单一的真相来源”。这意味着你想要做的并不是明确允许的。您将不得不使用GraphQL来维护设计模式。 –

您可以根据授权结果进行查询。在你的待办事项例如:

  1. 问授权服务器,其待办事项你被允许看,
  2. SELECT * FROM todos WHERE owner IN [<permitted owners]]

GraphQL不完全建议你应该如何使用它。对于Facebook,您必须了解他们尊重许多策略,因此决定让GraphQL保持在业务层之上(否则它仍然有意义)。为了解决你提到的问题,他们已经实现了缓存以及异步处理。这样,他们整理并缓存您的数据请求,从而更容易地检索先前查询的项目。

就你而言,如果你不需要业务层,你可以决定在存储层上面添加GraphQL。

GraphQL应该被看作是API的设计模式。确保数据/实体模型具有数据检索标准(也就是单一的真实来源),以及使大型系统的数据认证和API集成过程更加容易。

寻找答案的另一轮我偶然从李拜伦流人关于这个问题的一些轻一些有趣的意见后:

存储层不应该没有处理授权,但它应该公开限制返回数据量的 的API。

在上述处理成千上万个待办事项的场景中,可以通过公开 (如getTodosByUserId)将其返回给特定用户。然后,业务逻辑层 将通过过滤切片结果来处理授权和分页。但是,如果用户拥有数千个待办事项,那么该怎么办?可能会向存储层 添加另一个筛选选项,例如getTodosByUserId({ userId: 1, completed: false })

Lee提出的“让我们谈论缓存”的重要结论是来自存储层的结果 应该像Redis或memcached一样易于缓存。提取 来自Redis的一千个待办事项,然后在您的业务逻辑层中对它们进行过滤和切片,可能比为每个请求查询SQL数据库要便宜得多 。