Справочник по синтаксису Common Expression Language для подключения к данным

В данном справочном руководстве рассматривается синтаксис языка выражений Common Expression Language (CEL), необходимый для создания выражений для директив @auth(expr:) и @check(expr:) .

Полная справочная информация по CEL представлена ​​в спецификации CEL .

Тестовые переменные передаются в запросах и мутациях.

Синтаксис @auth(expr) позволяет получать доступ к переменным из запросов и мутаций и проверять их.

Например, вы можете включить переменную операции, такую ​​как $status , используя vars.status .

mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")

Данные, доступные для выражений: request, response, this

Вы используете данные для:

  • Оценка с использованием выражений CEL в директивах @auth(expr:) и @check(expr:)
  • Присваивание с использованием серверных выражений, <field>_expr .

Как выражения CEL ` @auth(expr:) , так и @check(expr:) могут оценивать следующее:

  • request.operationName
  • vars (псевдоним для request.variables )
  • auth (псевдоним для request.auth )

При изменении типа данных вы можете получить доступ к содержимому следующих элементов и присвоить его:

  • response (для проверки частичных результатов в многошаговой логике)

Кроме того, выражения @check(expr:) могут оцениваться следующим образом:

  • this (значение текущего поля)
  • response (для проверки частичных результатов в многошаговой логике)

Привязка request.operationName

В привязке request.operarationName хранится тип операции: запрос или изменение.

Привязка vars (request.vars)

Функция привязки vars позволяет вашим выражениям получать доступ ко всем переменным, переданным в вашем запросе или мутации.

Вы можете использовать vars.<variablename> в выражении в качестве псевдонима для полного request.variables.<variablename> `.

# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")

Привязка auth (request.auth)

Authentication идентифицирует пользователей, запрашивающих доступ к вашим данным, и предоставляет эту информацию в качестве привязки, на основе которой вы можете строить свои выражения.

В фильтрах и выражениях вы можете использовать auth в качестве псевдонима для request.auth .

В привязке аутентификации содержится следующая информация:

  • uid : Уникальный идентификатор пользователя, присваиваемый пользователю, отправившему запрос.
  • token : Карта значений, собранных в процессе Authentication .

Для получения более подробной информации о содержимом файла auth.token см. раздел «Данные в токенах аутентификации».

response связывания

В привязке response содержатся данные, которые сервер собирает в ответ на запрос или изменение , по мере того, как эти данные собираются .

По мере выполнения операции, по мере успешного завершения каждого этапа, response содержатся данные об успешно завершенных этапах.

Структура привязки response определяется формой связанной с ним операции, включая (множественные) вложенные поля и (при необходимости) встроенные запросы.

Обратите внимание, что при доступе к данным ответа на встроенный запрос поля могут содержать любые типы данных в зависимости от данных, запрошенных во встроенном запросе; при доступе к данным, возвращаемым полями мутаций, такими как _insert и _delete , они могут содержать ключи UUID, количество удалений, значения NULL (см. справочник по мутациям ).

Например:

  • В мутации, содержащей встроенный запрос, привязка response содержит данные для поиска по адресу response.query.<fieldName>.<fieldName>.... , в данном случае response.query.todoList и response.query.todoList.priority .
mutation CheckTodoPriority(
  $uniqueListName: String!
) {
  # This query is identified as `response.query`
  query @check(expr: "response.query.todoList.priority == 'high'", message: "This list is not for high priority items!") {
    # This field is identified as `response.query.todoList`
    todoList(where: { name: $uniqueListName }) {
      # This field is identified as `response.query.todoList.priority`
      priority
    }
  }
}
  • В многошаговой мутации, например, с несколькими полями _insert , привязка response содержит частичные данные по response.<fieldName>.<fieldName>.... , в данном случае, response.todoList_insert.id .
mutation CreateTodoListWithFirstItem(
  $listName: String!,
  $itemContent: String!
) @transaction {
  # Step 1
  todoList_insert(data: {
    id_expr: "uuidV4()",
    name: $listName,
  })
  # Step 2:
  todo_insert(data: {
    listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
    content: $itemContent,
  })
}

this переплет

Привязка this выполняет директива @check связана с полем, к которому она прикреплена. В простом случае вы можете оценивать результаты запроса, содержащие одно значение.

mutation UpdateMovieTitle (
  $movieId: UUID!,
  $newTitle: String!)
  @auth(level: USER)
  @transaction {
  # Step 1: Query and check
  query @redact {
    moviePermission( # Look up a join table called MoviePermission with a compound key.
      key: {movieId: $movieId, userId_expr: "auth.uid"}
    ) {
      # Check if the user has the editor role for the movie. `this` is the string value of `role`.
      # If the parent moviePermission is null, the @check will also fail automatically.
      role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Если возвращаемое поле встречается несколько раз, поскольку какой-либо предок является списком, каждое вхождение проверяется с помощью this к соответствующему значению.

Для любого заданного пути, если предок равен null или [] , то поле не будет достигнуто, и вычисление CEL для этого пути будет пропущено. Другими словами, вычисление происходит только тогда, когда this значение null или не равно null , но никогда не undefined .

Если само поле представляет собой список или объект, this имеет ту же структуру (включая всех потомков, выбранных в случае объектов), как показано в следующем примере.

mutation UpdateMovieTitle2($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query {
    moviePermissions( # Now we query for a list of all matching MoviePermissions.
      where: {movieId: {eq: $movieId}, userId: {eq_expr: "auth.uid"}}
    # This time we execute the @check on the list, so `this` is the list of objects.
    # We can use the `.exists` macro to check if there is at least one matching entry.
    ) @check(expr: "this.exists(p, p.role == 'editor')", message: "You must be an editor of this movie to update title") {
      role
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Сложный синтаксис выражений

Более сложные выражения можно создавать, комбинируя операторы && и || .

mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")

В следующем разделе описаны все доступные операторы.

Операторы и приоритет операторов

Используйте следующую таблицу в качестве справочника по операторам и их соответствующему приоритету.

Пусть заданы произвольные выражения a и b , поле f и индекс i .

Оператор Описание Ассоциативность
a[i] a() af Индекс, вызов, доступ к полю слева направо
!a -a Унарное отрицание справа налево
a/ba%ba*b операторы умножения слева направо
a+b ab Аддитивные операторы слева направо
a>b a>=b a<b a<=b Реляционные операторы слева направо
a in b Наличие в списке или на карте слева направо
type(a) == t Сравнение типов, где t может быть bool, int, float, number, string, list, map, timestamp или duration. слева направо
a==ba!=b Операторы сравнения слева направо
a && b Условное И слева направо
a || b Условное ИЛИ слева направо
a ? true_value : false_value Тройное выражение слева направо

Данные в токенах аутентификации

Объект auth.token может содержать следующие значения:

Поле Описание
email Адрес электронной почты, связанный с учетной записью, если таковой имеется.
email_verified true если пользователь подтвердил наличие доступа к адресу email . Некоторые провайдеры автоматически проверяют принадлежащие им адреса электронной почты.
phone_number Номер телефона, связанный с учетной записью, если таковой имеется.
name Отображаемое имя пользователя, если оно задано.
sub Идентификатор пользователя в Firebase (Firebase UID). Этот идентификатор уникален в рамках одного проекта.
firebase.identities Словарь всех идентификаторов, связанных с учетной записью этого пользователя. Ключами словаря могут быть любые из следующих: email , phone , google.com , facebook.com , github.com , twitter.com . Значения словаря представляют собой массивы уникальных идентификаторов для каждого поставщика идентификации, связанного с учетной записью. Например, auth.token.firebase.identities["google.com"][0] содержит первый идентификатор пользователя Google, связанный с учетной записью.
firebase.sign_in_provider Указан поставщик услуг авторизации, использованный для получения этого токена. Может принимать одно из следующих значений: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com .
firebase.tenant Идентификатор арендатора (tenantId), связанный с учетной записью, если он присутствует. Например, tenant2-m6tyz

Дополнительные поля в токенах JWT ID

Вы также можете получить доступ к следующим полям auth.token :

Пользовательские заявки на получение токенов
alg Алгоритм "RS256"
iss Эмитент Адрес электронной почты учетной записи службы вашего проекта
sub Предмет Адрес электронной почты учетной записи службы вашего проекта
aud Аудитория "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Выпущено в момент Текущее время в секундах с начала эпохи UNIX.
exp Срок действия Время в секундах с начала эпохи UNIX, по истечении которого срок действия токена истекает. Максимальное время может быть на 3600 секунд позже , чем iat UNIX.
Примечание: это управляет только временем истечения срока действия самого пользовательского токена . Но как только вы авторизуете пользователя с помощью signInWithCustomToken() , он останется авторизованным на устройстве до тех пор, пока его сессия не будет аннулирована или пользователь не выйдет из системы.
<claims> (необязательно) Дополнительные пользовательские утверждения, которые можно включить в токен и получить к ним доступ через auth.token (или request.auth.token ) в выражениях. Например, если вы создадите пользовательское утверждение adminClaim , вы сможете получить к нему доступ через auth.token.adminClaim .