使用中继进行身份验证和访问控制

2024-01-22

Facebook 的官方说法是 Relay 是“故意不了解身份验证机制 https://stackoverflow.com/a/32544246/741970在Relay存储库的所有示例中,身份验证和访问控制是一个单独的关注点。在实践中,我还没有找到一种简单的方法来实现这种分离。

中继存储库中提供的示例都具有带有viewer假设有一个用户的字段。该用户可以访问所有内容。

然而,实际上,一个应用程序有很多用户,每个用户对每个节点的访问程度不同。

假设我在 JavaScript 中有这个模式:

export const Schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: 'Query',
        fields: () => ({
            node: nodeField,
            user: {
                type: new GraphQLObjectType({
                    name: 'User',
                    args: {
                        // The `id` of the user being queried for
                        id: { type: new GraphQLNonNull(GraphQLID) },
                        // Identity the user who is querying
                        session: { type: new GraphQLInputObjectType({ ... }) },
                    },
                    resolve: (_, { id, session }) => {
                        // Given `session, get user with `id`
                        return data.getUser({ id, session });
                    }
                    fields: () => ({
                        name: {
                            type: GraphQLString,
                            resolve: user => {
                                // Does `session` have access to this user's
                                // name?
                                user.name
                            }
                        }
                    })
                })
            }
        })
    })
});

从查询用户的角度来看,某些用户是完全私密的。其他用户可能只向查询用户公开某些字段。因此,要获取用户,客户端不仅必须提供他们正在查询的用户 ID,而且还必须标识自己,以便进行访问控制。

随着控制访问的需求逐渐渗透到图表中,这似乎很快就会变得复杂。

此外,我需要控制每个根查询的访问,例如nodeField。我需要确保每个节点都实现nodeInterface.

所有这些看起来都是大量的重复性工作。是否有任何已知的模式可以简化此操作?我是否错误地思考了这个问题?


不同的应用程序对访问控制的形式有非常不同的要求,因此将某些内容融入到基本的 Relay 框架或 GraphQL 参考实现中可能没有意义。

我见过的一种非常成功的方法是将隐私/访问控制融入到数据模型/数据加载器框架中。每次加载对象时,您不仅会通过 id 加载它,还会提供查看器的上下文。如果查看者看不到该对象,则该对象将无法加载就好像它不存在一样以防止甚至泄漏该对象的存在。该对象还保留查看器上下文,并且某些字段可能具有限制访问权限,这些字段在从对象返回之前会进行检查。在较低级别的数据加载机制中进行烘焙有助于确保较高级别产品/GraphQL 代码中的错误不会泄漏私有数据。

在一个具体的例子中,我可能不被允许看到某个用户,因为他已经阻止了我。您可能可以看到他的一般情况,但不能看到他的电子邮件,因为您不是他的朋友。

在代码中是这样的:

var viewer = new Viewer(getLoggedInUser());
User.load(id, viewer).then(
  (user) => console.log("User name:", user.name),
  (error) => console.log("User does not exist or you don't have access.")
)

尝试在 GraphQL 级别实现可见性很可能会泄露信息。想一想 Facebook 的 GraphQL 实现中访问用户的多种方式:

node($userID) { name }
node($postID) { author { name } }
node($postID) { likers { name } }
node($otherUserID) { friends { name } }

所有这些查询都可以加载用户名,如果用户阻止了您,则它们都不应返回用户或其名称。对所有这些字段进行访问控制并且不要忘记在任何地方进行检查是错过检查的秘诀某处.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用中继进行身份验证和访问控制 的相关文章

随机推荐