Как настроить права доступа в PocketBase: руководство по API Rules
API Rules — механизм контроля доступа в PocketBase. Для каждой коллекции вы задаёте выражения-фильтры, которые определяют, кто может выполнять операции (list, view, create, update, delete). Если выражение возвращает true — операция разрешена, false — запрещена. Правила выполняются на стороне сервера до выполнения запроса.
Синтаксис API Rules: основы
Правила записываются в поле фильтра коллекции. Пустая строка "" означает «разрешено всем». Отсутствие правила null означает «запрещено всем» (только superuser через Admin UI).
# Открытый доступ для всех
listRule: ""
# Запрещено всем (только Admin UI)
listRule: null # или не заполнять поле
# Только авторизованные
listRule: @request.auth.id != ""
# Только владелец
listRule: user = @request.auth.id
Доступные переменные
@request.auth — данные авторизованного пользователя:
@request.auth.id— ID пользователя (пустая строка если не авторизован)@request.auth.email— email@request.auth.verified— верифицирован ли email@request.auth.collectionName— имя коллекции (для custom auth)@request.auth.fieldName— любое поле из коллекции пользователя
@request.body — тело запроса (при создании/обновлении):
@request.body.fieldName— значение поля из запроса
@request.query — URL-параметры запроса.
@now — текущее время (UTC).
Операторы сравнения
= равно
!= не равно
> больше
>= больше или равно
< меньше
<= меньше или равно
~ содержит (LIKE '%value%')
!~ не содержит
?= хотя бы один элемент в relation равен значению
?!= хотя бы один элемент не равен
?~ хотя бы один элемент содержит
Логические операторы
&& И (AND)
|| ИЛИ (OR)
! НЕ (NOT)
Паттерн 1: Публичная коллекция (блог, каталог)
Для контента, который должен быть доступен без авторизации:
# Коллекция: articles
listRule: published = true
viewRule: published = true || author = @request.auth.id
createRule: @request.auth.id != ""
updateRule: author = @request.auth.id
deleteRule: author = @request.auth.id
Объяснение:
- Список: только опубликованные статьи видны всем
- Просмотр: опубликованные — всем, черновики — только автору
- Создание: только авторизованные
- Редактирование/удаление: только автор своих записей
Паттерн 2: Приватная коллекция (личные данные)
Пользователь видит и редактирует только свои данные:
# Коллекция: notes (личные заметки)
listRule: owner = @request.auth.id
viewRule: owner = @request.auth.id
createRule: @request.auth.id != ""
updateRule: owner = @request.auth.id
deleteRule: owner = @request.auth.id
При создании записи нужно автоматически установить owner. Сделайте это через хук или через API Rule на тело запроса:
# Убедиться что owner в body = текущий пользователь
createRule: @request.auth.id != "" && @request.body.owner = @request.auth.id
Паттерн 3: Командный доступ (SaaS с ролями)
Стандартная структура: team_members со связями team + user + role.
# Коллекция: projects
listRule: team.members.user ?= @request.auth.id
viewRule: team.members.user ?= @request.auth.id
createRule: team.members.user ?= @request.auth.id &&
team.members.role ?!= "viewer"
updateRule: team.members.user ?= @request.auth.id &&
team.members.role ?!= "viewer"
deleteRule: team.owner = @request.auth.id ||
(team.members.user ?= @request.auth.id &&
team.members.role ?= "admin")
Разбор:
team.members.user ?= @request.auth.id— «в relation members хотя бы одна запись, где user равен текущему пользователю»team.members.role ?!= "viewer"— «хотя бы одна запись в members, где role не viewer»
Важно: оператор ?= проверяет «хотя бы один» — это нужно для multiple relations (один пользователь может быть членом нескольких команд). Убедитесь, что фильтры пересекаются корректно.
Паттерн 4: Публичное чтение, авторизованная запись
Для форумов, комментариев, рейтингов:
# Коллекция: comments
listRule: ""
viewRule: ""
createRule: @request.auth.id != ""
updateRule: author = @request.auth.id
deleteRule: author = @request.auth.id ||
@request.auth.role = "moderator"
Паттерн 5: Верифицированные пользователи
Требовать подтверждения email перед доступом:
# Коллекция: premium_content
listRule: @request.auth.id != "" && @request.auth.verified = true
viewRule: @request.auth.id != "" && @request.auth.verified = true
createRule: @request.auth.id != "" && @request.auth.verified = true
updateRule: @request.auth.id != "" && @request.auth.verified = true
deleteRule: @request.auth.id != "" && @request.auth.verified = true
Паттерн 6: Контент с временным доступом
Доступ к записи до определённой даты:
# Коллекция: temp_access
viewRule: user = @request.auth.id && expires_at >= @now
listRule: user = @request.auth.id && expires_at >= @now
Паттерн 7: Роли через поле в коллекции users
Если роли хранятся прямо в users (не в отдельной таблице):
# В коллекции users добавьте поле role: Select [user, moderator, admin]
# Коллекция: reports
listRule: @request.auth.id != ""
viewRule: owner = @request.auth.id || @request.auth.role = "admin"
createRule: @request.auth.id != ""
updateRule: owner = @request.auth.id || @request.auth.role ~ "admin"
deleteRule: @request.auth.role = "admin"
Правила для Admin API (суперпользователь)
Admin UI и Admin API обходят все API Rules — это принципиально важно для безопасности. Никогда не используйте Admin API-токен на клиентской стороне.
// ❌ Неправильно — Admin token в браузере
const pb = new PocketBase('https://myapp.com')
pb.authStore.save(ADMIN_TOKEN, null) // Никогда!
// ✅ Правильно — Admin token только на сервере
// Server-side (Next.js API Route / Server Action)
const adminPb = new PocketBase(process.env.PB_URL!)
await adminPb.admins.authWithPassword(
process.env.PB_ADMIN_EMAIL!,
process.env.PB_ADMIN_PASSWORD!
)
// Теперь можно делать операции, обходящие API Rules
const allUsers = await adminPb.collection('users').getFullList()
Отладка API Rules
Если правило работает неожиданно — включите логирование в PocketBase:
./pocketbase serve --dev
# В dev-режиме все запросы логируются с деталями фильтрации
Тестирование правил через REST API с curl:
# Тест без авторизации
curl http://localhost:8090/api/collections/posts/records
# Тест с авторизацией
TOKEN=$(curl -X POST http://localhost:8090/api/collections/users/auth-with-password \
-H "Content-Type: application/json" \
-d '{"identity":"test@test.com","password":"password123"}' | jq -r '.token')
curl http://localhost:8090/api/collections/posts/records \
-H "Authorization: $TOKEN"
Расширенные случаи: правила через хуки
Иногда API Rules недостаточно для сложной логики. Используйте хуки для проверок:
// pb_hooks/check_quota.pb.js
// Проверить лимит перед созданием (не реализуемо через API Rules)
onRecordCreateRequest((e) => {
const userId = e.requestInfo().auth?.id
if (!userId) return e.next()
// Считаем существующие записи пользователя
const count = $app.countRecords(
'projects',
$dbx.exp('owner = {:userId}', { userId })
)
// Проверяем лимит по плану
const user = e.requestInfo().auth
const maxProjects = user.getString('plan') === 'pro' ? 50 : 5
if (count >= maxProjects) {
return e.error(403, `Достигнут лимит проектов (${maxProjects}) для вашего тарифа`)
}
e.next()
}, 'projects')
FAQ
Как разрешить доступ только суперадминам в PocketBase?
Оставьте все API Rules пустыми (null) — доступ только через Admin UI и Admin API. Для частичного доступа добавьте поле is_admin: Bool в коллекцию users и используйте @request.auth.is_admin = true в правилах.
Почему ?= а не = для проверки relation?
Когда поле — это relation с возможностью множественных значений (multiple select или back-relation через другую коллекцию), нужен оператор ?= (хотя бы один элемент). Оператор = работает только для scalar-полей (текст, число, ID одной записи). Если используете = для relation — PocketBase вернёт ошибку или неверный результат.
Можно ли ограничить поля, которые возвращает API?
Через поле fields в запросе: ?fields=id,title,author. Но это контролируется клиентом, не сервером. Чтобы скрыть поля на уровне сервера — используйте хук onRecordAfterReadRequest для удаления полей из ответа, или создайте отдельную коллекцию-view с нужными полями.
Как тестировать API Rules без написания клиентского кода?
Через встроенный API Explorer в Admin UI: http://localhost:8090/_/#/collections/YOUR_COLLECTION/api. Он показывает все endpoint'ы и позволяет тестировать запросы прямо в браузере с авторизацией или без.
Работают ли API Rules для realtime-подписок?
Да. Realtime-подписки через pb.collection('posts').subscribe('*', ...) также проверяются через API Rules. Пользователь получает только те события (create/update/delete), записи которых он имеет право читать согласно viewRule.