Фильтрация подписок на события AWS AppSync для пользователя Cognito
У меня есть следующая схема:
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
Однако я не знаю, что добавить в шаблон сопоставления запросов.
2 ответа
Я думаю, что первый шаг для фильтрации подписок на основе пользователя проще всего сделать с небольшим обновлением вашей схемы, разбив входную форму на отдельные входы для мутации. В частности:
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.
До тех пор, пока Appsync не улучшится, вот как я выполнил подписку, которая позволяет пользователю подписываться только на события, которые соответствуют его собственному userID, используя схему, которую я разместил выше:
Шаблон сопоставления запроса:
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"userID": $util.dynamodb.toDynamoDBJson($ctx.identity.username),
"eventID": { "S" : "0bfe0d7c-b469-441e-95f6-788fe300f76d" }
},
}
Шаблон сопоставления запросов предназначен только для внешнего вида (веб-консоль Appsync не позволит вам сохранить данные, не заполнив его чем-либо допустимым). Он выполняет жесткий код поиска каждый раз, когда кто-то делает запрос на подписку. Это ничего, кроме успеха, и данные выбрасываются. Так работает подписка в Appsync.
Шаблон отображения ответов подписки:
#if(${context.identity.username} != ${context.arguments.userID})
$utils.unauthorized()
#else
##User is authorized, but we return null to continue
null
#end
Вот где происходит волшебство. В основном это говорит о том, что если пользователь не запрашивал подписку на события с тем же именем пользователя, что и у себя, - return unauthorized
, Если пользователь запросил подписку на события с тем же идентификатором пользователя, что и вошедшая в систему учетная запись, null
(null - это способ успешного продолжения шаблона отображения ответов (т. е. без ошибок).
Для полноты, вот как выглядит запрос клиента:
const eventSub = `subscription eventSub($userID: String!) {
onCreateEvent(userID: $userID) {
userID
email_hash
eventID
type
data
dateTime
}
}`;