无AAD用户认证下将ADX仪表盘嵌入多租户SaaS应用的可行性验证请求
多租户SaaS应用嵌入ADX仪表盘(无AAD用户认证)的可行性与问题解决
问题背景
我希望借助Azure Data Explorer(ADX)的仪表盘嵌入功能,为多租户SaaS应用构建分析仪表盘,同时需要在ADX上实现行级安全保障数据隔离。当前遇到的核心问题:
- 我们不使用Azure AD(AAD)对用户进行认证,计划为每个SaaS租户创建独立的AAD应用
- 已实现后端通过AAD应用执行ADX查询,但前端iframe嵌入仪表盘时,传递应用级令牌无法完成认证
- 怀疑ADX仪表盘嵌入不支持以AAD应用为主体的访问控制,需验证该方案的可行性
已实现的后端查询代码
var clusterName = "<adx-cluster-name>"; var dbName = "<adx-db-name>"; var appId = "<AppId>"; var appTenantId = "<tenantId>"; var clientSecret = _configuration["ADX:ClientSecret"]; var kcsb = new KustoConnectionStringBuilder($"https://{clusterName}.westeurope.kusto.windows.net/{dbName}") .WithAadApplicationKeyAuthentication( appId, clientSecret, appTenantId); var queryString = @" ['events'] | where Name == 'Apply' | summarize sum(ItemCount) by startofmonth(TimeGenerated), tostring(Properties['tenantId']) "; var ret = new List<string>(); var client = KustoClientFactory.CreateCslQueryProvider(kcsb); var queryResult = client.ExecuteQuery($"{queryString}"); while (queryResult.Read()) { DateTime time = queryResult.GetDateTime(0); string tenantId = queryResult.GetString(1); long itemCount = queryResult.GetInt64(2); var line = String.Format("{0}\t{1,-20}\t{2}", time, itemCount, tenantId); ret.Add(line); }
前端认证相关代码
后端获取令牌代码
var clusterName = "<adx-cluster-name>"; var dbName = "<adx-db-name>"; var appId = "<AppId>"; var appTenantId = "<tenantId>"; var clientSecret = _configuration["ADX:ClientSecret"]; var kustoUri = $"https://{clusterName}.westeurope.kusto.windows.net"; var authClient = ConfidentialClientApplicationBuilder.Create(appId) .WithAuthority($"https://login.microsoftonline.com/{appTenantId}") .WithClientSecret(clientSecret) .Build(); var result = authClient.AcquireTokenForClient( new[] { $"{kustoUri}/.default" } ).ExecuteAsync().Result; var bearerToken = result.AccessToken;
前端传递令牌代码
const scope = event.data.scope === 'query' ? analyticsAuthQuery.data.adxLink + "/.default" : event.data.scope; event.source?.postMessage({ type: "postToken", message: analyticsAuthQuery.data.adxToken, scope: scope });
iframe定义
<iframe title="Analytics Dashboard" className={styles.iframe} src="https://dataexplorer.azure.com/dashboards/?f-IFrameAuth=true&f-PersistAfterEachRun=false&f-Homepage=false&f-ShowPageHeader=false&f-ShowNavigation=false&f-DisableExploreQuery=false" ></iframe>
可行性验证与解决方案
1. 方案可行性结论
该方案完全可行,ADX仪表盘嵌入(预览版)支持使用AAD应用令牌进行认证,但需满足两个核心前提:
- AAD应用已被授予ADX集群/数据库的对应权限(如Viewer、Database User角色)
- 令牌的受众、范围与ADX的权限模型匹配
- 行级安全可通过ADX的原生行级安全策略实现,结合AAD应用身份标识过滤租户数据
2. 前端iframe认证失败的解决步骤
(1)修正AAD应用的ADX权限
确保AAD应用被授予ADX数据库的访问权限,在ADX查询编辑器中执行以下命令:
// 授予数据库用户权限 .add database <db-name> users ('aadapp=<app-id>;<tenant-id>') // 或授予只读查看权限(推荐仪表盘场景) .add database <db-name> viewers ('aadapp=<app-id>;<tenant-id>')
(2)调整iframe的src参数
必须指定具体的仪表盘ID,而非通用入口,正确格式:
<iframe title="Analytics Dashboard" className={styles.iframe} src="https://dataexplorer.azure.com/dashboards/<dashboard-id>?f-IFrameAuth=true&f-PersistAfterEachRun=false&f-Homepage=false&f-ShowPageHeader=false&f-ShowNavigation=false&f-DisableExploreQuery=false" ></iframe>
提示:
可从ADX仪表盘的分享界面获取
(3)修正前端令牌传递逻辑
传递的scope必须与令牌请求的scope完全一致,无需动态调整,直接使用ADX集群的.default范围:
event.source?.postMessage({ type: "postToken", message: analyticsAuthQuery.data.adxToken, scope: "https://<cluster-name>.westeurope.kusto.windows.net/.default" });
(4)验证令牌有效性
使用JWT解码工具检查令牌关键字段:
aud:必须等于你的ADX集群URL(如https://<cluster-name>.westeurope.kusto.windows.net)roles:包含ADX授予的权限(如kusto.databaseViewer)appid:与你的AAD应用ID完全匹配
3. 行级安全(RLS)实现建议
基于AAD应用ID创建行级安全策略,实现租户数据隔离:
// 创建过滤函数,通过当前应用ID匹配租户ID .create-or-alter function FilterTenantData() { let currentAppId = current_principal_details().AppId; // 替换为你的租户ID与应用ID的映射逻辑,此处假设应用ID直接对应租户ID Properties['tenantId'] == currentAppId } // 为events表启用行级安全策略 .create-or-alter row level security policy TenantRLS on events all FilterTenantData()
内容的提问来源于stack exchange,提问作者user232548
相关产品推荐
相关产品推荐

