Prisma с политиками Supabase RLS

Для недавней задачи мне пришлось настроить Prisma для учета политик RLS (безопасность на уровне строк), настроенных в Supabase. Этого, как вы знаете, трудно достичь, так как по умолчанию Prisma открывает прямое соединение с базой данных, и это также с пользователем postgres, у которого есть разрешения на обход любой политики RLS.

Это краткое описание того, как я решил эту проблему и заставил Prisma работать с политиками RLS, настроенными в Supabase.

Беремся за роль

Первым шагом было убедиться, что Prisma не подключается к базе данных как пользователь postgres. Для этого я настроил новую роль, которая будет иметь LOGIN разрешений (чтобы позволить Prisma использовать эти учетные данные) и пароль.

CREATE ROLE myprismauser LOGIN PASSWORD 'testPWD1'

Как только это было сделано, я обновил URL-адрес базы данных, который использует Prisma, добавив эти данные.

DATABASE_URL=postgresql://myprismauser:testPWD1@db.mydbstr.supabase.co:5432/postgres

Когда я проверил это с помощью простого npx prisma db pull, я получил ответ о том, что в базе данных нет таблиц. Это произошло потому, что к роли нужно было добавить дополнительные разрешения. (Обратитесь к этой проблеме Github — https://github.com/prisma/prisma/issues/3041)

GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to myprismauser;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public to myprismauser;
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public to myprismauser;

Вот и все, роль настроена и готова к использованию.

Здесь важно отметить, что я не использую схему Supabase auth для управления политикой. Вместо этого я буду использовать пользовательские переменные для управления доступом, поэтому, если вы ищете способ связать Supabase Auth с Prisma, эта статья не для вас. (Я скоро напишу еще один о том, как это сделать, короче говоря, просто установите current_user_id на идентификатор Supabase вошедшего пользователя)

Политика RLS

Теперь, что касается фактической политики RLS, я настроил тестовую таблицу test_rls, на которой я установил новую политику для управления SELECT.

Эта политика возвращает все строки, в которых переменная app.current_role равна столбцу role в таблице test_rls.

Реализация Призмы

С этой настройкой мне теперь нужно было настроить Prisma для установки этой переменной перед запросом. Я нашел это решение в очень полезной ветке — https://github.com/prisma/prisma/issues/5128, пожалуйста, обязательно прочитайте ее полностью, так как она дает хорошее представление о том, как работает это решение, и о любых потенциальных возможностях. недостатки и др.

Я использую фреймворк Serverless для настройки Graphql API, который использует Prisma для управления доступом к данным. Я не буду вдаваться в подробности о том, как устанавливается свойство userRole, так как это будет зависеть от логики вашего собственного приложения. Кроме того, как указано в приведенной выше проблеме с Git, это должно быть перемещено в промежуточное программное обеспечение, но я показываю преобразователь здесь только для того, чтобы показать, как его можно использовать.

getTestRLSData: async ({ prisma, userRole = "" }) => {
  const resp = await prisma.$transaction([
    prisma.$executeRawUnsafe(`SET app.current_role = ${userRole}`),
    prisma.test_rls.findMany(),
  ]);
  return resp;
},

Причина, по которой я использовал executeRawUnsafe вместо executeRaw, заключалась в том, что при его использовании я получал ошибку. executeRawUnsafe, как следует из названия, небезопасно использовать, так как оно открывает приложение для атак SQL-инъекций. Будьте предельно осторожны при использовании этого и, если возможно, избегайте его вообще. Подробнее о его использовании читайте здесь — https://www.prisma.io/docs/concepts/components/prisma-client/raw-database-access#executerawunsafe

Приведенный выше преобразователь теперь позволяет мне выбирать строки на основе роли пользователя.

Если у вас есть какие-либо мысли о том, как улучшить эту настройку, или вы видите какие-либо потенциальные недостатки, не стесняйтесь оставлять комментарии. Я хотел бы услышать ваши мысли по этому поводу.