4

我有以下架构:

input CreateEventInput {
    userID: String!
    eventID: ID!
    type: String!
    data: String
    dateTime: AWSDateTime!
}

type Mutation {
    createEvent(input: CreateEventInput!): event
}

type Subscription {
    onCreateEvent(): event
        @aws_subscribe(mutations: ["createEvent"])

createEvent解析器设置userID如下:

"key" : {
        "userID" : $util.dynamodb.toDynamoDBJson($context.identity.username),
        "eventID" : $util.dynamodb.toDynamoDBJson($util.autoId())
    }

我想限制订阅,以便仅将记录userID = $context.identity.username返回给用户。

有谁知道如何设置这个?我想我需要一个关于订阅的解析器,但我找不到一个明确的例子,你有一个主分区键 ( userID) 和主排序键 ( eventID)。

我非常感谢任何帮助或指导。如果需要,我可以更改架构或数据库。

更新

我相信我可以将订阅响应映射模板设置为:

#if(${context.identity.username} != ${context.arguments.userID})
    $utils.unauthorized()
#else
##User is authorized, but we return null to continue
    null
#end

但是,我不知道在请求映射模板中放什么。

4

2 回答 2

5

我认为基于用户过滤订阅的第一步最容易通过对您的架构进行轻微更新来完成,方法是将“输入”形状分解为突变的单个输入。具体来说:

type mutation {
  createEvent(userID: String!, eventID: ID!, type: String!, 
    data: String, dateTime: AWSDateTime!): event
}
... other stuff...
type Subscription {
  onCreateEvent(userId: String!): event
  @aws_subscribe(mutations: ["createEvent"])
}

对此有几点说明:

1) 这假设您希望这是订阅的要求。如果不是,如果您希望它成为可选规则,请删除 !。根据您的评论,我相信您会想要它。

2)订阅过滤器(这是订阅操作中的 userId 参数)要求过滤器在突变的响应中。因此,请确保当您在客户端上定义操作时,您在响应中包含 userId。

3) 这是应用订阅过滤器所必需的。服务不会知道 userId 是什么,除非它是突变的直接输入,将它放在内部和输入形状将不起作用。

现在,就确定用户不能只订阅其他人的用户名而言。我相信您正在查看此文档页面。这将起作用,完全有效,并且可以通过与该文档页面中的示例接近的内容来完成,但它基于具有权限查找表和 Dynamo 解析器。如果您没有或希望避免使用一个,稍作调整应该能够使其与无/本地解析器一起使用。如果没有权限表或任何要检查的东西,我强烈建议使用本地/无解析器。

具体来说,我相信您可以将响应映射模板中的内容移动到新的无/本地解析器的映射模板中......

#if(${context.identity.username} != ${context.arguments.userID})
    $utils.unauthorized()
#else
##User is authorized, but we return null to continue
    null
#end

...并让响应映射模板成为默认响应,那么您将拥有它,而权限表中没有不必要的基础设施,也没有设置不会发生的发电机交互的死代码。相反,所有这一切都会检查输入中的用户名与 Cognito 令牌中的用户名。

于 2018-10-30T06:16:44.020 回答
2

在 Appsync 改进之前,我是如何使用我在上面发布的架构完成一个只允许用户订阅与他们自己的 userID 匹配的事件的订阅:

请求映射模板:

{
    "version": "2017-02-28",
    "operation": "GetItem",
    "key": {
        "userID": $util.dynamodb.toDynamoDBJson($ctx.identity.username),
        "eventID": { "S" : "0bfe0d7c-b469-441e-95f6-788fe300f76d" }
    },
}

请求映射模板仅用于外观(Appsync Web 控制台不会让您在没有填充有效内容的情况下保存)每次有人发出订阅请求时都会进行硬编码查找。这只会成功,并且数据被丢弃。这就是订阅在 Appsync 中的工作方式。

订阅响应映射模板:

#if(${context.identity.username} != ${context.arguments.userID})
    $utils.unauthorized()
#else
##User is authorized, but we return null to continue
    null
#end

这就是魔法发生的地方。这基本上说如果用户没有请求订阅与他们自己用户名相同的事件 - 返回unauthorized。如果用户确实请求订阅具有与登录帐户相同的用户 ID 的事件,null(null 是响应映射模板成功继续的方式(即,不出错)。

为了彻底起见,客户端请求如下所示:

const eventSub = `subscription eventSub($userID: String!) {
  onCreateEvent(userID: $userID) {
    userID
    email_hash
    eventID
    type
    data
    dateTime
  }
}`;
于 2018-10-30T22:49:01.160 回答