GraphQL 编辑需要授权的字段的最佳实践

Posted

技术标签:

【中文标题】GraphQL 编辑需要授权的字段的最佳实践【英文标题】:GraphQL best practice on redacting fields that require authorization 【发布时间】:2020-08-17 13:11:28 【问题描述】:

考虑一个User 类型,带有一个email 字段,对于某些“匿名”用户,只有在请求得到适当授权的情况下才能访问该字段。其他用户可以公开显示他们的电子邮件。

type User 
  name: String!
  "Anonymous users have the email only accessible to admins"
  email: String!

email 解析器中为匿名用户处理该字段的这两种方法的优缺点是什么?

    throw 如果请求未经授权。在这种情况下, email 需要声明为可空的 String 而不是 String!、or the entire query will error。 客户端可能希望将the errorsdata 匹配。因为非匿名用户可以在未经授权的情况下访问他们的电子邮件,errorsdata 可能有不同数量的元素,所以这种匹配似乎不可能,至少对于 apollo-server,它没有t 返回每个 errors 元素中的任何内容,以指示它属于哪个 useremail 会误导匿名用户 null,将这种情况与从未添加过的电子邮件混淆。请记住,email 必须是 String,而不是 String!,所以null 电子邮件是合理的。 响应中有一个明确的errors 数组,所以这感觉像是“正确”的方法? 以编辑的形式返回电子邮件,例如[NOT AUTHORIZED TO ACCESS THIS USER'S EMAIL]。 这样可以保持对象完好无损,敏感电子邮件会出现明显错误,而不是误导“空”电子邮件。 email 可以保持不可为空 无需尝试将errorsdata 匹配。 响应中没有明确的 errors 数组,所以这感觉像是 hack。

请注意,对于数组,不能返回 REDACTED 表单,因为查询可能会要求数组中的字段(例如 anonUsers email )。唯一的选择是返回[](直接或通过throwing)。

我错过了什么吗?有没有关于这个主题的先前工作?我该如何做决定?

【问题讨论】:

联合类型会是一个好的用例吗?您可以有一个普通的User 类型和一个AnonymousUser 类型,并且可能有一些将它们分开的字段,例如is_anonymous。所以也许AnonymousUser 没有电子邮件字段,而User 有。 @A.Lau:这回避了问题。假设所有用户都是匿名的,只有授权的请求才能看到email;那么关于将errorsdata 匹配的意义就没有意义了,但其他的仍然存在。 也许 AnonymousUser email 可以是一个对象,这样你就可以显示你想要的任何消息/错误代码。 【参考方案1】:

我最近做了类似的事情,似乎最有效的是为基本用户类型创建一个界面。

interface UserInformation 
  id: ID!
  userName: String
  firstName: String!
  lastName: String
  avatarImage: String
  city: String
  ...

那么你会有两个独立的实现:

type UserPublic implements UserInformation 
  id: ID!
  userName: String
  firstName: String!
  lastName: String
  avatarImage: String
  ...

type UserPrivate implements UserInformation 
  id: ID!
  userName: String
  firstName: String!
  lastName: String
  avatarImage: String
  friends: [UserInformation!]
  pendingFriends: [UserInformation!]
  phone: String
  email: String
  birthday: DateTime
  ...

在公开用户时,您的所有其他查询和类型都使用UserInformation 基本接口类型。然后,您的 graphql 服务器仅返回 UserPublicUserPrivate,具体取决于用户拥有的访问权限类型。

在客户端你这样查询它:

query SomeQuery 
  getSomeData 
    user 
      id
      userName
      firstName
      lastName
      avatarImage
      ...on UserPrivate 
        email
        phone
      
      ...

然后您可以检查客户端返回的字段类型 (__typename) 是否为 UserPublicUserPrivate 并采取相应措施。

【讨论】:

以上是关于GraphQL 编辑需要授权的字段的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

在 Typescript 应用程序中管理生成的 graphql 模式的最佳实践

使用 Apollo 重新获取部分 GraphQL 查询的最佳实践?

如何操作 AWS AppSync 和 GraphQL 以符合 DynamoDB 最佳实践?

基于WPS的Word最佳实践系列(利用表格控制排版)

在graphql中,组合多个源中的字段共享一个共同值的多个源的最佳方法是啥?

在 Web API/OWIN 中使用大量声明的最佳实践