Metabase Widgets Controller¶
Контроллер: tech.ujin.api.MetabaseWidgetsController
Swagger Links¶
- Swagger UI
- OpenAPI YAML
- GET /api/metabase/widgets
- GET /api/metabase/widgets/{id}
- GET /api/metabase/widgets/by-ids
Документ описывает runtime-flow запроса GET /api/metabase/widgets и связанных GET /api/metabase/widgets/{id},
GET /api/metabase/widgets/by-ids.
1. Контракт запроса¶
Эндпоинты:
- GET /api/metabase/widgets/{id}
- GET /api/metabase/widgets/by-ids
Поддерживаемая аутентификация:
TokenAuth:- Header
token(основной вариант в OpenAPI) - Header
Authorization: Bearer <token>(runtime fallback) BasicAuth(LDAP):- Header
Authorization: Basic <base64(login:password)>
Прочие параметры:
- Header
X-BMS-DOMEN— опциональный выбор источника данных для routing только дляTokenAuth. Для LDAPBasicAuthзаголовок игнорируется. - Query
page(/api/metabase/widgets) — опциональный рекурсивный фильтр по имени вложенной папки (equalsIgnoreCase, послеtrim) или поcollectionId. - Query
structureOnly=true(/api/metabase/widgets) — вернуть дерево без embed JWT и без metadata lookup для каждого виджета.
2. Security chain и аутентификация¶
Фильтры для /api/metabase/**:
RoutingDataSourceFilterBasicAuthenticationFilter(Spring Security)LdapAuthFilterTokenAuthFilter
Что происходит:
RoutingDataSourceFilterдляTokenAuthнормализуетX-BMS-DOMEN, ищетdomain -> instance_idв кеше on-prem boxes и выбираетsource; для LDAP всегда используетсяdefault-source.BasicAuthenticationFilter+LdapAuthenticationProviderобрабатывают BasicAuth.LdapAuthFilter:- берет
uid(логин), - берет
entryUUIDиз LDAP principal (или делает lookup поuid), - читает filter-теги пользователя из сервисной БД,
- собирает
AccessContextиз всех назначенныхFILTER_BMS_ID/FILTER_INSTANCE_ID, - формирует
AuthenticatedUser(authSystemType=LDAP, ldapUserUuid=...), - выставляет контекстные заголовки
X-Ujin-User-Id,X-Ujin-Bms-Id. TokenAuthFilterсрабатывает только если аутентифицированный пользователь еще не установлен; поэтому LDAP-пользователь не перетирается token-flow.- Если ни LDAP, ни token не аутентифицировали пользователя, endpoint вернет
401.
Endpoint policy:
GET/PATCH /api/metabase/settings/widgets/access— толькоTokenAuth./api/metabase/settings/admin/**— толькоBasicAuth(LDAP) + login вapp.ldap.adminLogins.- Widgets/Favorites/Analytics endpoints — допускают
TokenAuthиBasicAuth.
3. Бизнес-алгоритм listWidgets¶
Метод: MetabaseWidgetsService.listWidgets(user, page).
3.1 Разрешенные виджеты и режим ACL¶
resolveAccessResolution(user):
- Для
AuthSystemType.TOKEN: allowedWidgetIdsизmetabase_widget_access(source_key + bms_id + role_id).applyRoleAccess=true.- Для
AuthSystemType.LDAP: allowedWidgetIdsизmetabase_tag_widget_accessчерез теги пользователя.deniedCollectionIdsизmetabase_user_tag_denied_collectionчерез пользователя.- если список пустой,
applyRoleAccess=falseи используется доступ только от корневых коллекций.
3.2 Корневые коллекции¶
MetabaseCollectionResolver:
TOKEN: используетсяmetabase.collections.root-names.token.LDAP:- читаются теги пользователя из
metabase_user_tag/metabase_access_tag; - root-коллекции определяются только тегами
ROOT_COLLECTION; - применяются маппинги
root-names.tag-roots(порядок как в YAML); - для unmapped тегов используется fallback: имя коллекции =
tag.code.
Если имя коллекции не найдено в Metabase, сервис завершит запрос ошибкой конфигурации:
No collection configured for name=....
3.3 Построение дерева и фильтры¶
Для каждой коллекции рекурсивно:
listSubcollections:GET /api/collection/{id}/items?models=collectionloadAllowedItems:GET /api/collection/{id}/items?models=dashboard,card
Фильтры MetabaseCollectionAccessService:
archived == false- role-tags (
#ADMIN,#manager, ...) - BMS-tags (
#BMS-<id>/#!BMS-<id>) - ACL-фильтр по
allowedWidgetIdsтолько когдаapplyRoleAccess=true
Важно: если userRole == null/blank, role-теги не ограничивают доступ.
Это штатно для LDAP-flow.
Для token-flow с x_enterprise_id дерево дополнительно фильтруется по enterprise-тегам в description папок и
виджетов:
- стандартный формат:
#ENTERPRISE_ID-<id>; теги можно перечислять через запятую; - если enterprise-теги не заданы, элемент считается общим;
- если enterprise-теги заданы, элемент доступен только для matching
x_enterprise_id; - фильтр применяется и к подпапкам: если подпапка не прошла по enterprise-тегу, вся её дочерняя ветка не сканируется.
Для LDAP-flow перед page-фильтром дополнительно:
- из дерева вырезаются все подпапки из deny-list;
- дочерние папки запрещенной подпапки не сканируются и их виджеты не попадают ни в tree, ни в index для
/widgets/{id}и/widgets/by-ids.
После этого применяется page-фильтр:
- поиск идет рекурсивно по всем уровням дерева;
- совпадение по
group.id == pageилиgroup.name.equalsIgnoreCase(page); - в ответ попадают только matching-группы со своей вложенной структурой.
4. Генерация embed JWT¶
Для каждого виджета:
- Нормализация типа:
card -> question. - Получение
embedding_params(из collection item или черезGET /api/dashboard/{id}/GET /api/card/{id}). EmbeddingParamsResolverразрешает locked-параметры (bms_id,bms_ids,instance_ids).- Для
TokenAuthподдерживается толькоbms_idкак одиночное число. - Для
LDAPподдерживаются толькоbms_idsиinstance_idsкак списки значений из admin-assigned тегов. GuestTokenServiceподписывает JWT (HMAC256,metabase.embedding.secret, TTL из конфигурации).
Поведение при неизвестном locked-параметре:
/api/metabase/widgets— проблемный виджет пропускается./api/metabase/widgets/{id}и/api/metabase/widgets/by-ids—403.
Если structureOnly=true:
- embed JWT не генерируются;
GuestTokenServiceне вызывается;- metadata lookup для dashboard/card не делается.
5. Кеши¶
- on-prem domain mapping:
app.datasource-routing.mapping-cache-ttl-seconds(default300) - root collection id:
metabase.collections.root-ttl-seconds - collections list:
metabase.collections.collections-ttl-seconds - collection items:
metabase.collections.items-ttl-seconds - metadata (
/api/card|dashboard/{id}):metabase.collections.metadata-ttl-seconds
6. Ошибки¶
401— нет валидной аутентификации403— запрошенный виджет недоступен / ошибка locked-параметров502— ошибка интеграции с Metabase400— ошибка входных данных500— внутренняя ошибка
7. Diagram (PlantUML)¶
docs/controllers/metabase-widgets-list-request.puml