Dmi*_*sky 15 javascript graphql graphql-js relayjs
来自Facebook的官方消息是,Relay" 故意不了解身份验证机制".在中继存储库中的所有示例中,身份验证和访问控制是一个单独的问题.实际上,我还没有找到一种简单的方法来实现这种分离.
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
}
}
})
})
}
})
})
});
Run Code Online (Sandbox Code Playgroud)
从查询用户的角度来看,一些用户完全是私人的.其他用户可能只向查询用户公开某些字段.因此,为了获得用户,客户端不仅必须提供他们要查询的用户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.")
)
Run Code Online (Sandbox Code Playgroud)
尝试在GraphQL级别实现可见性有很多泄漏信息的可能性.想想在Facebook的GraphQL实现中访问用户的多种方式:
node($userID) { name }
node($postID) { author { name } }
node($postID) { likers { name } }
node($otherUserID) { friends { name } }
Run Code Online (Sandbox Code Playgroud)
所有这些查询都可以加载用户的名称,如果用户阻止了您,则他们都不应该返回用户或其名称.拥有所有这些领域的访问控制,并没有在任何地方忘了检查是失踪检查食谱的地方.
我发现如果使用 GraphQL ,处理身份验证很容易rootValue,当针对架构执行查询时,它会传递到执行引擎。该值在所有执行级别都可用,并且对于存储访问令牌或标识当前用户的任何内容非常有用。
如果您使用的是express-graphql中间件,则可以将会话加载到GraphQL中间件之前的中间件中,然后配置GraphQL中间件以将该会话放入根值中:
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 }
})));
Run Code Online (Sandbox Code Playgroud)
然后,该会话可在架构中的任何深度使用:
new GraphQLObjectType({
name: 'MyType',
fields: {
myField: {
type: GraphQLString,
resolve(parentValue, _, { rootValue: { session } }) {
// use `session` here
}
}
}
});
Run Code Online (Sandbox Code Playgroud)
您可以将其与“面向查看者”的数据加载配对以实现访问控制。查看https://github.com/facebook/dataloader它有助于创建这种数据加载对象并提供批处理和缓存。
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)),
};
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2580 次 |
| 最近记录: |