我们正在制作 Power BI 报告。每天从我们开发的 ASP.NET Core Web API 获取一次数据。 OAuth2 被用作 .NET Core 应用程序中的身份验证框架,由于使用 Swagger 进行了测试,因此运行良好。
我们想要在.NET Core应用程序中对Power BI进行身份验证。可以通过多种方式完成:
基本身份验证
以前,身份验证是通过基本身份验证(用户名和密码)完成的,效果很好。但现在,我们计划使其更加安全。
服务负责人
我们认为使用服务主体是适合我们案例的正确方法。我假设 Power BI 中的服务主体身份验证在幕后使用 OAuth2 客户端凭据流。
我们通过以下方式在 Power BI Web 应用程序中配置服务主体:
Power BI => Workspace => Semantic Model => Settings => Data Source Credentials => Edit Credentials
我们在Entra ID中的APP注册中添加了各类API权限。这是:
此外,我们还在 Power BI 中将应用程序注册添加为具有管理员权限的安全组:
如您所见,具有应用程序注册的安全组以及应用程序注册本身已添加到具有管理员权限的工作区。
当我们想要为 Power BI 配置身份验证以将 ASP.NET Core Web API 作为服务主体访问时,我们会收到以下错误:
无法更新数据源凭据。
如何解决无法在 ASP.NET Core Web API 中将 Power BI 验证为服务主体的问题?
我认为我们没有向 Power BI 提供足够的信息,因为 Power BI 不要求其他信息,例如 OAuth2 令牌的范围和 URL。 所以,我没有告诉 Power BI,这是生成令牌的 URL:
https://login.microsoftonline.com/azure-tenant-guid/oauth2/v2.0/token
.
您可以利用服务主体来验证 Power BI。
要使用服务主体对 Power BI 进行身份验证,请检查以下内容:
创建 Microsoft Entra ID 应用程序并授予 Power Bi 应用程序类型权限:
创建了 Azure 安全组并将服务主体添加为成员:
启用
Service principals can access read-only admin APIs
添加安全组,如下所示:
以上设置大约需要15分钟才能体现。
使用以下代码使用客户端凭证流程生成访问令牌并调用 Power Bi API:
class Program
{
private static string tenantId = "TenantID";
private static string clientId = "ClientID";
private static string clientSecret = "ClientSecret";
private static string scope = "https://analysis.windows.net/powerbi/api/.default";
static async Task Main(string[] args)
{
try
{
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var tokenRequestContext = new Azure.Core.TokenRequestContext(new[] { scope });
var token = await clientSecretCredential.GetTokenAsync(tokenRequestContext);
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
var response = await httpClient.GetAsync("https://api.powerbi.com/v1.0/myorg/groups");
if (response.IsSuccessStatusCode)
{
string responseData = await response.Content.ReadAsStringAsync();
Console.WriteLine("Response from Power BI API:");
Console.WriteLine(responseData);
}
else
{
Console.WriteLine($"Error: {response.StatusCode}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
}
}