使用中继进行身份验证和访问控制 [英] Authentication and Access Control with Relay

查看:91
本文介绍了使用中继进行身份验证和访问控制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自Facebook的官方消息是,Relay是故意不了解身份验证机制。在中继存储库中的所有示例中,身份验证和访问控制是一个单独的问题。在实践中,我还没有找到一种简单的方法来实现这种分离。

The official line from Facebook is that Relay is "intentionally agnostic about authentication mechanisms." In all the examples in the Relay repository, authentication and access control are a separate concern. In practice, I have not found a simple way to implement this separation.

Relay存储库中提供的示例都具有带查看器的根模式假设有一个用户的字段。该用户可以访问所有内容。

The examples provided in the Relay repository all have root schemas with a viewer field that assumes there is one user. And that user has access to everything.

然而,实际上,应用程序拥有许多用户,每个用户对每个节点都有不同程度的访问权限。

However, in reality, an application has has many users and each user has different degrees of access to each node.

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

Suppose I have this schema in 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,而且还必须标识自己以便可以进行访问控制。

Some users are entirely private from the perspective of the querying user. Other users might only expose certain fields to the querying user. So to get a user, the client must not only provide the user ID they are querying for, but they must also identify themselves so that access control can occur.

这似乎随着控制访问的需要逐渐减少图表,快速变得复杂。

This seems to quickly get complicated as the need to control access trickles down the graph.

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

Furthermore, I need to control access for every root query, like nodeField. I need to make sure that every node implementing nodeInterface.

所有这些似乎都是重复工作。有没有任何已知的模式来简化这个?我是否错误地考虑了这个问题?

All of this seems like a lot of repetitive work. Are there any known patterns for simplifying this? Am I thinking about this incorrectly?

推荐答案

我发现如果使用GraphQL,处理身份验证很容易 rootValue ,传递给对模式执行查询时的执行引擎。此值在所有执行级别都可用,对于存储访问令牌或标识当前用户的任何内容都很有用。

I found that handling authentication is easy if you make use of the GraphQL rootValue, which is passed to the execution engine when the query is executed against the schema. This value is available at all levels of execution and is useful for storing an access token or whatever identifies the current user.

如果您使用的是 express-graphql 中间件,您可以在GraphQL中间件之前的中间件中加载会话,然后配置GraphQL中间件以将该会话放入根值:

If you're using the express-graphql middleware, you can load the session in a middleware preceding the GraphQL middleware and then configure the GraphQL middleware to place that session into the root value:

function getSession(req, res, next) {
  loadSession(req).then(session => {
    req.session = session;
    next();
  }).catch(
    res.sendStatus(400);
  );
}

app.use('/graphql', getSession, graphqlHTTP(({ session }) => ({
  schema: schema,
  rootValue: { session }
})));

此会话随后可在架构的任何深度获得:

This session is then available at any depth in the schema:

new GraphQLObjectType({
  name: 'MyType',
  fields: {
    myField: {
      type: GraphQLString,
      resolve(parentValue, _, { rootValue: { session } }) {
        // use `session` here
      }
    }
  }
});

您可以将其与面向查看者的数据加载配对以实现访问控制。查看 https://github.com/facebook/dataloader ,它有助于创建此类数据加载对象和提供批处理和缓存。

You can pair this with "viewer-oriented" data loading to achieve access control. Check out https://github.com/facebook/dataloader which helps create this kind of data loading object and provides batching and caching.

function createLoaders(authToken) {
  return {
    users: new DataLoader(ids => genUsers(authToken, ids)),
    cdnUrls: new DataLoader(rawUrls => genCdnUrls(authToken, rawUrls)),
    stories: new DataLoader(keys => genStories(authToken, keys)),
  };
}

这篇关于使用中继进行身份验证和访问控制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆