学习教程
授权

授权

¥Authorization

将授权逻辑委托给业务逻辑层

¥Delegate authorization logic to the business logic layer

授权是一种业务逻辑,描述给定的用户/会话/上下文是否有权执行操作或查看数据。例如:

¥Authorization is a type of business logic that describes whether a given user/session/context has permission to perform an action or see a piece of data. For example:

“只有作者才能看到他们的草稿”

¥“Only authors can see their drafts”

强制实现这种行为应该发生在 业务逻辑层 中。人们很容易将授权逻辑放置在 GraphQL 层中,如下所示:

¥Enforcing this kind of behavior should happen in the business logic layer. It is tempting to place authorization logic in the GraphQL layer like so:

const postType = new GraphQLObjectType({
  name: 'Post',
  fields: {
    body: {
      type: GraphQLString,
      resolve(post, args, context, { rootValue }) {
        // return the post body only if the user is the post's author
        if (context.user && (context.user.id === post.authorId)) {
          return post.body
        }
        return null
      }
    }
  }
})

请注意,我们通过检查帖子的 authorId 字段是否等于当前用户的 id 来定义 “作者拥有一篇文章”。你能找出问题所在吗?我们需要为服务的每个入口点复制此代码。然后,如果授权逻辑没有完全保持同步,用户可能会根据他们使用的 API 看到不同的数据。哎呀!我们可以通过 单一事实来源 进行授权来避免这种情况。

¥Notice that we define “author owns a post” by checking whether the post’s authorId field equals the current user’s id. Can you spot the problem? We would need to duplicate this code for each entry point into the service. Then if the authorization logic is not kept perfectly in sync, users could see different data depending on which API they use. Yikes! We can avoid that by having a single source of truth for authorization.

在学习 GraphQL 或原型设计时,在解析器内定义授权逻辑是很好的。但是,对于生产代码库,请将授权逻辑委托给业务逻辑层。这是一个例子:

¥Defining authorization logic inside the resolver is fine when learning GraphQL or prototyping. However, for a production codebase, delegate authorization logic to the business logic layer. Here’s an example:

// Authorization logic lives inside postRepository
const postRepository = require('postRepository');
 
const postType = new GraphQLObjectType({
  name: 'Post',
  fields: {
    body: {
      type: GraphQLString,
      resolve(post, args, context, { rootValue }) {
        return postRepository.getBody(context.user, post)
      }
    }
  }
})

在上面的示例中,我们看到业务逻辑层要求调用者提供用户对象。如果你使用的是 GraphQL.js,则应将 User 对象填充到解析器第四个参数中的 context 参数或 rootValue 上。

¥In the example above, we see that the business logic layer requires the caller to provide a user object. If you are using GraphQL.js, the User object should be populated on the context argument or rootValue in the fourth argument of the resolver.

我们建议将完全水合的 User 对象而不是不透明的令牌或 API 密钥传递给业务逻辑层。这样,我们就可以在请求处理管道的不同阶段处理 authentication 和授权的不同问题。

¥We recommend passing a fully-hydrated User object instead of an opaque token or API key to your business logic layer. This way, we can handle the distinct concerns of authentication and authorization in different stages of the request processing pipeline.