授权
将授权逻辑委托给业务逻辑层
大多数 API 需要根据请求者来保护对某些类型数据的访问权限,GraphQL 也不例外。在 身份验证 中间件确认用户身份并将该信息传递给 GraphQL 层之后,GraphQL 执行才应开始。但在那之后,您仍然需要确定经过身份验证的用户是否被允许查看请求中包含的特定字段提供的数据。在这一页中,我们将探讨 GraphQL 模式如何支持授权。
类型和字段授权
授权是一种业务逻辑,描述了给定的用户/会话/上下文是否有权限执行操作或查看数据。例如
“只有作者才能看到他们的草稿”
执行此行为应发生在 业务逻辑层。让我们考虑在模式中定义的以下 Post 类型
type Post {
authorId: ID!
body: String
}在此示例中,我们可以想象当请求最初到达服务器时,身份验证中间件将首先检查用户的凭据,并将有关其身份的信息添加到 GraphQL 请求的 context 对象中,以便在执行期间此数据在每个字段解析器中都可用。
如果帖子的正文应该只对撰写它的人可见,那么我们需要检查经过身份验证的用户的 ID 是否与帖子的 authorId 值匹配。将授权逻辑放在帖子 body 字段的解析器中可能很诱人,如下所示
function Post_body(obj, args, context, info) {
// Return the post body only if the user is the post's author
if (context.user && context.user.id === obj.authorId) {
return obj.body;
}
return null;
}请注意,我们通过检查帖子的 authorId 字段是否等于当前用户的 id 来定义“作者拥有帖子”。您能发现问题吗?我们需要为进入服务的每个入口点复制此代码。然后,如果授权逻辑没有完全保持同步,用户看到的数据可能会因他们使用的 API 而异。哎呀!我们可以通过为授权建立一个 单一事实来源 来避免这种情况,而不是将其放在 GraphQL 层。
在学习 GraphQL 或原型制作时,在解析器内部定义授权逻辑是可以的。但是,对于生产代码库,请将授权逻辑委托给业务逻辑层。这是一个示例,说明如何单独实现 Post 类型的字段的授权
// Authorization logic lives inside `postRepository`
export const postRepository = {
getBody({ user, post }) {
const isAuthor = user?.id === post.authorId;
return isAuthor ? post.body : null;
},
};帖子 body 字段的解析器函数将调用 postRepository 方法,而不是直接实现授权逻辑
import { postRepository } from "postRepository";
function resolvePostBody(obj, args, context, info) {
// Return the post body only if the user is the post's author
return postRepository.getBody({
user: context.user,
post: obj,
});
}在上面的示例中,我们看到业务逻辑层要求调用者提供一个用户对象,该对象可在 GraphQL 请求的 context 对象中找到。我们建议将一个完全充实的用户对象而不是一个不透明的令牌或 API 密钥传递给您的业务逻辑层。通过这种方式,我们可以在请求处理管道的不同阶段处理 身份验证 和授权的不同关注点。
使用类型系统指令
在上面的示例中,我们看到了如何通过在字段解析器中调用的函数将授权逻辑委托给业务逻辑层。一般来说,建议在此层中执行所有授权逻辑,但如果您决定在 GraphQL 层中实现授权,一种方法是使用 类型系统指令。
例如,可以在模式中定义一个像 @auth 这样的指令,并带有参数,指示用户必须具备哪些角色或权限才能访问应用了该指令的类型和字段提供的数据
directive @auth(rule: Rule) on FIELD_DEFINITION
enum Rule {
IS_AUTHOR
}
type Post {
authorId: ID!
body: String @auth(rule: IS_AUTHOR)
}GraphQL 实现需要确定 @auth 指令如何影响执行,当客户端发出请求包含 Post 类型的 body 字段时。但是,授权逻辑应仍委托给业务逻辑层。
总结
总结 GraphQL 中的授权建议
- 授权逻辑应委托给业务逻辑层,而不是 GraphQL 层
- 执行开始后,GraphQL 服务器应决定发起请求的客户端是否有权访问包含的字段数据
- 可以定义类型系统指令并将其添加到模式中的类型和字段上,以应用通用的授权规则
分页
探索 GraphQL 中的不同分页策略,从简单的切片到完全连接的边和节点。