Пользовательские требования Supabase

Я создал репозиторий [GitHub Repository (https://github.com/supabase-community/supabase-custom-claims)], который позволяет легко реализовать пользовательские требования для вашего приложения на основе Supabase. (Supabase — это бэкенд-сервис с открытым исходным кодом, который использует PostgreSQL в качестве базы данных и GoTrue для аутентификации. Он также делает много других интересных вещей, но эти вопросы выходят за рамки данной статьи).

Это всего лишь один из способов реализации custom claims для проекта Supabase. Цель здесь — просто добавить данные JSON к маркеру доступа JWT, который получает аутентифицированный пользователь при входе в ваше приложение. Этот токен (и, соответственно, custom claims, содержащиеся в этом токене) может быть прочитан и использован как вашим приложением, так и сервером базы данных PostgreSQL. Эти custom claims хранятся в поле raw_app_meta_data таблицы users в схеме auth. (auth.users.raw_app_meta_data)

Чтобы сделать эту технику как можно более переносимой, я реализовал ее с помощью набора функций PostgreSQL, которые можно вызывать из любого клиентского языка Supabase, который может вызывать функции PostgreSQL. (Это охватывает множество языков программирования!).

Содержание
  1. ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
  2. Что такое пользовательские утверждения?
  3. Какие типы данных можно хранить в пользовательских утверждениях?
  4. Где хранятся эти пользовательские утверждения?
  5. Существуют ли какие-либо ограничения на именование?
  6. Зачем использовать пользовательские формулы вместо того, чтобы просто создать таблицу?
  7. Каковы недостатки использования пользовательских утверждений?
  8. Как написать запрос, чтобы найти всех пользователей, у которых есть определенный пользовательский набор требований?
  9. примеры
  10. В чем разница между auth.users.raw_app_meta_data и auth.users.raw_user_meta_data?
  11. Соображения безопасности
  12. Загрузка
  13. Использование функций
  14. Внутри редактора запросов
  15. get_claims(uid uuid).
  16. get_claim(uid uuid, текст претензии)
  17. set_claim(uid uuid, claim text, value jsonb)
  18. delete_claim(uid uuid, claim text)
  19. Функции и триггеры внутри PostgreSQL
  20. is_claims_admin().
  21. get_my_claims()
  22. get_my_claim(claim TEXT)
  23. Внутри политики RLS (Row Level Security)
  24. Получение данных о претензиях из локальных данных сеанса
  25. Установка данных претензий из вашего приложения (с помощью .rpc())
  26. Предупреждение
  27. Заключение

ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ

Что такое пользовательские утверждения?

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

Например:

plan: "TRIAL"
user_level: 100
group_name: "Super Guild!"
joined_on: "2022-05-20T14:28:18.217Z"
group_manager: false
items: ["toothpick", "string", "ring"]
Войти в полноэкранный режим Выйти из полноэкранного режима

Какие типы данных можно хранить в пользовательских утверждениях?

В утверждении можно хранить любые данные в формате JSON. Вы можете хранить строку, число, булеву функцию, дату (как строку), массив или даже сложный, вложенный, полный объект JSON.

Где хранятся эти пользовательские утверждения?

Пользовательские утверждения хранятся в таблице auth.users, в колонке raw_app_meta_data для пользователя.

Существуют ли какие-либо ограничения на именование?

В настоящее время система Supabase Auth System (GoTrue) использует следующие пользовательские утверждения: provider и providers, поэтому НЕ используйте их. Любая другая допустимая строка может быть использована в качестве имени для вашей пользовательской формулы (формул).

Зачем использовать пользовательские формулы вместо того, чтобы просто создать таблицу?

В основном, из-за производительности. Пользовательские требования хранятся в маркере безопасности, который пользователь получает при входе в систему, и эти требования доступны базе данных PostgreSQL в качестве параметра конфигурации, т.е. current_setting('request.jwt.claims', true). Таким образом, база данных получает доступ к этим значениям немедленно, без необходимости выполнять какие-либо операции на диске.

Это может показаться тривиальным, но это может оказать значительное влияние на масштабируемость, если вы используете утверждения в политике RLS (Row Level Security), поскольку потенциально это может устранить тысячи (или даже миллионы) обращений к базе данных.

Каковы недостатки использования пользовательских утверждений?

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

Вы можете принудительно обновить текущий токен сессии, вызвав supabase.auth.update({}) на клиенте, но если утверждение изменено серверным процессом или администратором утверждений вручную, нет простого способа уведомить пользователя о том, что его утверждения изменились. Однако вы можете предоставить кнопку «обновить» или функцию обновления внутри вашего приложения, чтобы обновлять формулы в любое время.

Как написать запрос, чтобы найти всех пользователей, у которых есть определенный пользовательский набор требований?

примеры

найти всех пользователей, у которых claims_admin имеет значение true

select * from auth.users where (auth.users.raw_app_meta_data->'claims_admin')::bool = true;

найти всех пользователей, у которых userlevel больше 100

select * from auth.users where (auth.users.raw_app_meta_data->'userleval')::numeric > 100;

найти всех пользователей, чья userrole установлена на "MANAGER"

(примечание для строк необходимо добавить двойные кавычки, так как данные хранятся в виде JSONB)

В чем разница между auth.users.raw_app_meta_data и auth.users.raw_user_meta_data?

Таблица auth.users, используемая Supabase Auth (GoTrue), имеет оба поля raw_app_meta_data и raw_user_meta_data.

raw_user_meta_data предназначена для данных профиля и может быть создана и изменена пользователем. Например, эти данные могут быть установлены при регистрации пользователя: sign-up-with-additional-user-meta-data или эти данные могут быть изменены пользователем с помощью auth-update.

raw_app_meta_data предназначена для использования прикладным уровнем и используется GoTrue для обработки аутентификации (Например, утверждения provider и providers используются GoTrue для отслеживания поставщиков аутентификации). raw_app_meta_data по умолчанию недоступна пользователю.

Соображения безопасности

Если вы хотите усилить безопасность, чтобы пользовательские утверждения могли быть установлены или удалены только из редактора запросов или внутри ваших функций или триггеров PostgreSQL, отредактируйте функцию is_claims_admin(), чтобы запретить ее использование пользователями приложения (без использования через API / Postgrest). Инструкции включены в функцию.

По умолчанию, использование разрешено через API, но возможность устанавливать или удалять претензии ограничена только теми пользователями, у которых пользовательская функция claims_admin имеет значение true. Это позволит вам создать раздел «admin» в вашем приложении, который позволит назначенным пользователям изменять пользовательские утверждения для других пользователей вашего приложения.

Загрузка

Если единственный способ установить или удалить претензии требует, чтобы утверждение claims_admin было установлено в true, а ни у одного пользователя нет такого утверждения, как я могу редактировать пользовательские претензии из своего приложения?

Ответ заключается в «загрузке» пользователя путем выполнения следующей команды в окне редактора запросов Supabase:

select set_claim('03acaa13-7989-45c1-8dfb-6eeb7cf0b92e', 'claims_admin', 'true');

где 03acaa13-7989-45c1-8dfb-6eeb7cf0b92e — это id вашего пользователя-администратора, найденный в auth.users.

Использование функций

Внутри редактора запросов

Вы можете получать, устанавливать и удалять утверждения для любого пользователя на основе его id (uuid) с помощью следующих функций:

get_claims(uid uuid).

Возвращает объект JSON, содержащий все пользовательские претензии для пользователя.

get_claim(uid uuid, текст претензии)

Возвращает объект JSON для одной претензии пользователя.

set_claim(uid uuid, claim text, value jsonb)

Это устанавливает конкретную претензию для пользователя. Вы можете отправить сюда любые допустимые данные JSON, включая числа, текст, булевы, массивы или полные сложные вложенные объекты JSON.

delete_claim(uid uuid, claim text)

Эта функция удаляет пользовательскую претензию для пользователя.

Функции и триггеры внутри PostgreSQL

При использовании пользовательских утверждений внутри функции или триггера PostgreSQL вы можете использовать любую из функций, показанных в разделе выше: Внутри редактора запросов.

Кроме того, вы можете использовать следующие функции, специфичные для текущего зарегистрированного пользователя:

is_claims_admin().

Возвращает true, если утверждение claims_admin установлено в true. Это означает, что пользователю разрешено выполнять функции, описанные выше (set_claim и т.д.).

get_my_claims()

Возвращает JSON-объект, содержащий все пользовательские претензии для текущего пользователя.

get_my_claim(claim TEXT)

Возвращает объект JSON для одной претензии для текущего пользователя.

Внутри политики RLS (Row Level Security)

Чтобы использовать пользовательские утверждения в политике RLS, вы обычно используете get_my_claim для проверки конкретного утверждения для текущего зарегистрированного пользователя. Например, вы можете проверить, является ли пользователь подписчиком вашего приложения, прежде чем разрешить доступ к таблице. Что-то вроде этого:

Синтаксис здесь немного странный, потому что функция get_my_claim возвращает объект JSON, поэтому если вы проверяете строку, вам нужно заключить ее в кавычки. Вы можете проверять и другие типы (числовые, булевы и т.д.).

Получение данных о претензиях из локальных данных сеанса

Вы можете извлечь информацию о претензиях из объекта session, который вы получаете, когда пользователь вошел в систему. Например:

supabase.auth.onAuthStateChange((_event, session) => {
  if (session?.user) {
    console.log(session?.user?.app_metadata) // show custom claims
  }
})
Вход в полноэкранный режим Выход из полноэкранного режима

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

Установка данных претензий из вашего приложения (с помощью .rpc())

Следующие функции могут быть использованы только «администратором претензий», то есть пользователем, у которого пользовательское утверждение claims_admin установлено на true:

(Примечание: эти функции позволяют просматривать, устанавливать и удалять претензии для любого пользователя вашего приложения, поэтому их целесообразно использовать в административной ветви вашего приложения только для пользователей высокого уровня с соответствующими правами безопасности (т.е. пользователей уровня claims_admin)).

Примеры TypeScript:

public get_claims = async (uid: string) => {
    const { data, error } = await supabase
        .rpc('get_claims', { uid });
    return { data, error };
}
public get_claim = async (uid: string, claim: string) => {
    const { data, error } = await supabase
        .rpc('get_claim', { uid, claim });
    return { data, error };
}
public set_claim = async (uid: string, claim: string, value: object) => {
    const { data, error } = await supabase
        .rpc('set_claim', { uid, claim, value });
    return { data, error };
}
public delete_claim = async (uid: string, claim: string) => {
    const { data, error } = await supabase
        .rpc('delete_claim', { uid, claim });
    return { data, error };
}
Вход в полноэкранный режим Выход из полноэкранного режима

Предупреждение

Обязательно следите за зарезервированными утверждениями в вашей конкретной среде разработки. Например, утверждения exp и role зарезервированы системой Supabase Realtime и могут вызвать проблемы, если вы попытаетесь использовать эти имена. Чтобы избежать этих потенциальных проблем, хорошей практикой является использование пользовательского идентификатора в ваших пользовательских формулах, например MY_COMPANY_item1, MY_COMPANY_item2 и т.д.

Заключение

Я надеюсь, что эта статья была вам полезна при разработке приложения с Supabase. Это всего лишь мой личный подход к работе с претензиями, поэтому не стесняйтесь использовать его в качестве отправной точки для вашего собственного подхода. Я с нетерпением жду, когда вы увидите, какие интересные вещи вы придумаете в своих приложениях!

Оцените статью
Procodings.ru
Добавить комментарий