具有 GraphQL 和 CognitoAuth 的用户数据存储设计模式 AWS AppSyn

Posted

技术标签:

【中文标题】具有 GraphQL 和 CognitoAuth 的用户数据存储设计模式 AWS AppSyn【英文标题】:User data storage design pattern AWS AppSyn with GraphQL and CognitoAuth 【发布时间】:2021-07-20 13:03:01 【问题描述】:

我在空闲时间第一次构建了一个无服务器网络应用程序。我已经使用 AWS Cognito 和 Amplify 完成了我的整个登录工作流程,但现在我很尴尬。

我想在 cognito 之外存储与用户相关的数据(如生日、显示用户名、头像图片 URL 等),但是因为我使用 cognito auth 设置了 appsync,所以我无法在注册时创建用户(由于授权问题,在用户验证之前)在数据库中。我没有将这些数据存储在 cognito 中,原因有两个:

    这些字段可能会在以后更改(例如添加或删除一个),并且 cognito 不允许删除属性。 根据我的阅读,AWS Cognito 不允许使用它们的属性进行反向搜索

我觉得这是一个完整的工作流程问题,我愿意接受建议,但我知道我只有在注册时才有一些用户数据(如显示用户名或生日)。

您可以在这里找到我的 AppSync graphql 配置(目前非常基本)

schema 
  query: Query
  mutation: Mutation
  subscription: Subscription


type Mutation 
  createUserData(input: CreateUserDataInput!): UserData
  deleteUserData(input: DeleteUserDataInput!): UserData
  updateUserData(input: UpdateUserDataInput!): UserData


type Query 
  getUserData(email: String!, id: ID!): UserData
  listUserData(filter: TableUserDataFilterInput, limit: Int, nextToken: String): UserDataConnection


type Subscription 
  onCreateUserData(email: String, first_name: String, id: ID, last_name: String, pseudoname: String): UserData @aws_subscribe(mutations : ["createUserData"])
  onDeleteUserData(email: String, first_name: String, id: ID, last_name: String, pseudoname: String): UserData @aws_subscribe(mutations : ["deleteUserData"])
  onUpdateUserData(email: String, first_name: String, id: ID, last_name: String, pseudoname: String): UserData @aws_subscribe(mutations : ["updateUserData"])


type UserData 
  avatar: String
  email: String!
  first_name: String
  id: ID!
  last_name: String
  pseudoname: String


type UserDataConnection 
  items: [UserData]
  nextToken: String


enum ModelAttributeTypes 
  _null
  binary
  binarySet
  bool
  list
  map
  number
  numberSet
  string
  stringSet


enum ModelSortDirection 
  ASC
  DESC


input CreateUserDataInput 
  avatar: String
  email: String!
  first_name: String
  id: ID!
  last_name: String
  pseudoname: String


input DeleteUserDataInput 
  email: String!
  id: ID!


input ModelBooleanInput 
  attributeExists: Boolean
  attributeType: ModelAttributeTypes
  eq: Boolean
  ne: Boolean


input ModelFloatInput 
  attributeExists: Boolean
  attributeType: ModelAttributeTypes
  between: [Float]
  eq: Float
  ge: Float
  gt: Float
  le: Float
  lt: Float
  ne: Float


input ModelIDInput 
  attributeExists: Boolean
  attributeType: ModelAttributeTypes
  beginsWith: ID
  between: [ID]
  contains: ID
  eq: ID
  ge: ID
  gt: ID
  le: ID
  lt: ID
  ne: ID
  notContains: ID
  size: ModelSizeInput


input ModelIntInput 
  attributeExists: Boolean
  attributeType: ModelAttributeTypes
  between: [Int]
  eq: Int
  ge: Int
  gt: Int
  le: Int
  lt: Int
  ne: Int


input ModelSizeInput 
  between: [Int]
  eq: Int
  ge: Int
  gt: Int
  le: Int
  lt: Int
  ne: Int


input ModelStringInput 
  attributeExists: Boolean
  attributeType: ModelAttributeTypes
  beginsWith: String
  between: [String]
  contains: String
  eq: String
  ge: String
  gt: String
  le: String
  lt: String
  ne: String
  notContains: String
  size: ModelSizeInput


input TableBooleanFilterInput 
  eq: Boolean
  ne: Boolean


input TableFloatFilterInput 
  between: [Float]
  contains: Float
  eq: Float
  ge: Float
  gt: Float
  le: Float
  lt: Float
  ne: Float
  notContains: Float


input TableIDFilterInput 
  beginsWith: ID
  between: [ID]
  contains: ID
  eq: ID
  ge: ID
  gt: ID
  le: ID
  lt: ID
  ne: ID
  notContains: ID


input TableIntFilterInput 
  between: [Int]
  contains: Int
  eq: Int
  ge: Int
  gt: Int
  le: Int
  lt: Int
  ne: Int
  notContains: Int


input TableStringFilterInput 
  beginsWith: String
  between: [String]
  contains: String
  eq: String
  ge: String
  gt: String
  le: String
  lt: String
  ne: String
  notContains: String


input TableUserDataFilterInput 
  avatar: TableStringFilterInput
  email: TableStringFilterInput
  first_name: TableStringFilterInput
  id: TableIDFilterInput
  last_name: TableStringFilterInput
  pseudoname: TableStringFilterInput


input UpdateUserDataInput 
  avatar: String
  email: String!
  first_name: String
  id: ID!
  last_name: String
  pseudoname: String

【问题讨论】:

【参考方案1】:

Cognito 支持所有 OIDC standard claims,它应该涵盖各种用例。对于未涵盖的其他属性,请考虑从您的注册表单中序列化数据并将其作为单个自定义属性存储在您的用户池中(如果它低于 2048 个字符的限制)。如果需要验证,请在 pre-signup lambda trigger 中进行。

要使该用户数据可用,请考虑创建另一个处理程序作为pre-token-generation trigger。在处理程序中,您可以反序列化表单数据并将它们作为声明添加到您的令牌中以便于使用。通过这个处理程序,您还可以将数据推送到您的数据库中,以供查询。

【讨论】:

以上是关于具有 GraphQL 和 CognitoAuth 的用户数据存储设计模式 AWS AppSyn的主要内容,如果未能解决你的问题,请参考以下文章

GraphQL:具有标量和 InputObjectType 的 UnionType

GraphQL 是不是具有与 REST 相同的缓存能力

Prisma、GraphQL 和 Apollo 中具有突变的数据关系和连接类型

具有自定义标量类型的 GraphQL.js 突变

具有多个别名和 Apollo (Vue.js) 的 GraphQL 查询

使用 NestJS、TypeORM、GraphQL 更新具有实体之间关系的 PSQL 表