Справочник по синтаксису 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)")

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

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

  • Оценка с помощью выражений 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 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 .
Примечание: это контролирует только время истечения срока действия самого пользовательского токена . Но как только вы введете пользователя с помощью signInWithCustomToken() , он останется в системе устройства до тех пор, пока его сеанс не будет аннулирован или пользователь не выйдет из системы.
<claims> (необязательно) Необязательные пользовательские утверждения для включения в токен, к которым можно получить доступ через auth.token (или request.auth.token ) в выражениях. Например, если вы создаете пользовательское утверждение adminClaim , вы можете получить к нему доступ с помощью auth.token.adminClaim .