Перейти к содержанию

Widgets flow (PlantUML)

Диаграмма рендерится из исходника .puml:

GET /api/metabase/widgets - runtime sequence (Token + LDAP)ClientSecurityFilterChainRoutingDataSourceFilterBasicAuthenticationFilterLdapAuthFilterTokenAuthFilterTokenAuthenticationProviderUserAuthServiceUserDataRepositoryMetabaseWidgetsControllerCurrentUserServiceMetabaseWidgetsServiceEmployeeAccessRepositoryRoleWidgetAccessRepositoryMetabaseCollectionResolverMetabaseCollectionAccessServiceMetabaseClientEmbeddingParamsResolverGuestTokenServiceClientSecurityFilterChainRoutingDataSourceFilterBasicAuthenticationFilterLdapAuthFilterTokenAuthFilterTokenAuthenticationProviderUserAuthServiceUserDataRepositoryMetabaseWidgetsControllerCurrentUserServiceMetabaseWidgetsServiceEmployeeAccessRepositoryRoleWidgetAccessRepositoryMetabaseCollectionResolverMetabaseCollectionAccessServiceMetabaseClientEmbeddingParamsResolverGuestTokenServiceClientSecurityFilterChainRoutingDataSourceFilterBasicAuthenticationFilterLdapAuthFilterTokenAuthFilterTokenAuthenticationProviderUserAuthServiceUserDataRepositoryMetabaseWidgetsControllerCurrentUserServiceMetabaseWidgetsServiceEmployeeAccessRepositoryRoleWidgetAccessRepositoryMetabaseCollectionResolverMetabaseCollectionAccessServiceMetabaseClientEmbeddingParamsResolverGuestTokenService1GET /api/metabase/widgets?page=...Headers: Authorization, token, X-BMS-DOMEN(optional for TokenAuth)2doFilter3resolve source by X-BMS-DOMEN for TokenAuthunknown/missing/LDAP -> default-source4continue5attempt BasicAuthalt[Authorization Basic present and LDAP bind success][no Basic header or bind failed]6Authentication(principal=DirContextOperations)7continue8doFilteralt[current authentication is LDAP principal][already AuthenticatedUser or anonymous]9resolve username (uid)10resolve entryUUIDalt[entryUUID missing in principal]11LDAP search by uid12findTagsByUserId(ldapUserUuid)13assigned tags14derive AccessContext from all FILTER_BMS_ID / FILTER_INSTANCE_ID tags15convert to AuthenticatedUser(authSystem=LDAP)16set request attr ujin.ldapLogin17skip conversion18continue19doFilteralt[AuthenticatedUser already exists (e.g. LDAP)][no authenticated user yet]20skip token auth21resolve token (header token first, then Bearer)alt[token exists][token missing]22authenticate(token)23authenticate(rawToken)24findByToken(rawToken)25Optional<UserData>26Optional<UserData>alt[valid user][invalid token]27Authentication(AuthenticatedUser, authSystem=TOKEN)28set SecurityContext + headers29AuthenticationException30clear SecurityContext31skip auth32authorize requestalt[unauthenticated][authenticated]33401 Authentication required34listWidgets(page)35currentUser()36AuthenticatedUser37listWidgets(user, page)38resolveAccessResolution(user)alt[user.authSystem == LDAP][user.authSystem == TOKEN]39findAllowedWidgetIdsByUser(bmsIds[], ldapUserUuid)40Set<Long>41findDeniedSubfolderIdsByUser(ldapUserUuid)42Set<Long>alt[ACL set is empty][ACL set not empty]43applyRoleAccess=false44roleForCollectionFilter=null45applyRoleAccess=true46roleForCollectionFilter=null47resolveRootCollectionIds(user)48findTagsByUserId(ldapUserUuid)49assigned tags50keep only ROOT_COLLECTION tags51apply tag-roots mapping in YAML order52unmapped tag -> fallback collection name = tag.code53listCollections()54collections[]55rootCollectionIds56findAllowedWidgetIds(bmsId, roleId, source_key)57Set<Long>58resolveRootCollectionIds(user)59listCollections()60collections[]61rootCollectionIds62applyRoleAccess=true63roleForCollectionFilter=user.roleloop[recursive collections tree from all rootCollectionIds]64listSubcollections(collectionId)65GET /api/collection/{id}/items?models=collection66subcollections[]alt[LDAP denied subfolder][visible collection]67skip subtree68loadAllowedItems(collectionId, userRole, bmsIds|bmsId, allowedWidgetIds, applyRoleAccess)69GET /api/collection/{id}/items?models=dashboard,card70items[]71filter archived72filter role tags (#ROLE)73filter BMS tags (#BMS / #!BMS)74apply allowedWidgetIds only when applyRoleAccess=true75allowed widgets[]alt[token request with x_enterprise_id]76filter enterprise tags in folder/widget description (#ENTERPRISE_ID-<id>)loop[each allowed widget]alt[structureOnly=true][structureOnly=false]77return widget without tokenalt[embedding_params already present in collection item][metadata required]78resolveLockedParams(user, metadata)79GET /api/{dashboard|card}/{id}80resource metadata.embedding_params81resolveLockedParams(user, metadata)alt[locked params supported][unknown locked param]82params map (Token: bms_id scalar; LDAP: bms_ids / instance_ids lists)83createToken(type, id, params)84signed token85WidgetAccessException86log warn and skip widget (for list endpoint)opt[page is provided]87recursively keep groups where name.equalsIgnoreCase(page)or group.id == page88WidgetsResponse(groups)89200 JSON
GET /api/metabase/widgets - runtime sequence (Token + LDAP)ClientSecurityFilterChainRoutingDataSourceFilterBasicAuthenticationFilterLdapAuthFilterTokenAuthFilterTokenAuthenticationProviderUserAuthServiceUserDataRepositoryMetabaseWidgetsControllerCurrentUserServiceMetabaseWidgetsServiceEmployeeAccessRepositoryRoleWidgetAccessRepositoryMetabaseCollectionResolverMetabaseCollectionAccessServiceMetabaseClientEmbeddingParamsResolverGuestTokenServiceClientSecurityFilterChainRoutingDataSourceFilterBasicAuthenticationFilterLdapAuthFilterTokenAuthFilterTokenAuthenticationProviderUserAuthServiceUserDataRepositoryMetabaseWidgetsControllerCurrentUserServiceMetabaseWidgetsServiceEmployeeAccessRepositoryRoleWidgetAccessRepositoryMetabaseCollectionResolverMetabaseCollectionAccessServiceMetabaseClientEmbeddingParamsResolverGuestTokenServiceClientSecurityFilterChainRoutingDataSourceFilterBasicAuthenticationFilterLdapAuthFilterTokenAuthFilterTokenAuthenticationProviderUserAuthServiceUserDataRepositoryMetabaseWidgetsControllerCurrentUserServiceMetabaseWidgetsServiceEmployeeAccessRepositoryRoleWidgetAccessRepositoryMetabaseCollectionResolverMetabaseCollectionAccessServiceMetabaseClientEmbeddingParamsResolverGuestTokenService1GET /api/metabase/widgets?page=...Headers: Authorization, token, X-BMS-DOMEN(optional for TokenAuth)2doFilter3resolve source by X-BMS-DOMEN for TokenAuthunknown/missing/LDAP -> default-source4continue5attempt BasicAuthalt[Authorization Basic present and LDAP bind success][no Basic header or bind failed]6Authentication(principal=DirContextOperations)7continue8doFilteralt[current authentication is LDAP principal][already AuthenticatedUser or anonymous]9resolve username (uid)10resolve entryUUIDalt[entryUUID missing in principal]11LDAP search by uid12findTagsByUserId(ldapUserUuid)13assigned tags14derive AccessContext from all FILTER_BMS_ID / FILTER_INSTANCE_ID tags15convert to AuthenticatedUser(authSystem=LDAP)16set request attr ujin.ldapLogin17skip conversion18continue19doFilteralt[AuthenticatedUser already exists (e.g. LDAP)][no authenticated user yet]20skip token auth21resolve token (header token first, then Bearer)alt[token exists][token missing]22authenticate(token)23authenticate(rawToken)24findByToken(rawToken)25Optional<UserData>26Optional<UserData>alt[valid user][invalid token]27Authentication(AuthenticatedUser, authSystem=TOKEN)28set SecurityContext + headers29AuthenticationException30clear SecurityContext31skip auth32authorize requestalt[unauthenticated][authenticated]33401 Authentication required34listWidgets(page)35currentUser()36AuthenticatedUser37listWidgets(user, page)38resolveAccessResolution(user)alt[user.authSystem == LDAP][user.authSystem == TOKEN]39findAllowedWidgetIdsByUser(bmsIds[], ldapUserUuid)40Set<Long>41findDeniedSubfolderIdsByUser(ldapUserUuid)42Set<Long>alt[ACL set is empty][ACL set not empty]43applyRoleAccess=false44roleForCollectionFilter=null45applyRoleAccess=true46roleForCollectionFilter=null47resolveRootCollectionIds(user)48findTagsByUserId(ldapUserUuid)49assigned tags50keep only ROOT_COLLECTION tags51apply tag-roots mapping in YAML order52unmapped tag -> fallback collection name = tag.code53listCollections()54collections[]55rootCollectionIds56findAllowedWidgetIds(bmsId, roleId, source_key)57Set<Long>58resolveRootCollectionIds(user)59listCollections()60collections[]61rootCollectionIds62applyRoleAccess=true63roleForCollectionFilter=user.roleloop[recursive collections tree from all rootCollectionIds]64listSubcollections(collectionId)65GET /api/collection/{id}/items?models=collection66subcollections[]alt[LDAP denied subfolder][visible collection]67skip subtree68loadAllowedItems(collectionId, userRole, bmsIds|bmsId, allowedWidgetIds, applyRoleAccess)69GET /api/collection/{id}/items?models=dashboard,card70items[]71filter archived72filter role tags (#ROLE)73filter BMS tags (#BMS / #!BMS)74apply allowedWidgetIds only when applyRoleAccess=true75allowed widgets[]alt[token request with x_enterprise_id]76filter enterprise tags in folder/widget description (#ENTERPRISE_ID-<id>)loop[each allowed widget]alt[structureOnly=true][structureOnly=false]77return widget without tokenalt[embedding_params already present in collection item][metadata required]78resolveLockedParams(user, metadata)79GET /api/{dashboard|card}/{id}80resource metadata.embedding_params81resolveLockedParams(user, metadata)alt[locked params supported][unknown locked param]82params map (Token: bms_id scalar; LDAP: bms_ids / instance_ids lists)83createToken(type, id, params)84signed token85WidgetAccessException86log warn and skip widget (for list endpoint)opt[page is provided]87recursively keep groups where name.equalsIgnoreCase(page)or group.id == page88WidgetsResponse(groups)89200 JSON