c# - 从我的 ASP.NET Core 5 Web 应用程序访问嵌入式 PowerBi 报告时,为什么会收到 MsalUiRequiredException 错误?
问题描述
我最近将我的 Web 应用程序从 Core 3.1 更改为 5,并开始使用 Identity.Web 进行身份验证。作为该过程的一部分,我引入了内存令牌缓存,应用程序完美地进行身份验证并按预期工作,但是,我还访问了嵌入的 PowerBi 报告并导致问题。这是我的代码和设置:
启动.cs
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(PowerBiServiceApi.RequiredScopes)
.AddInMemoryTokenCaches();
services.AddScoped(typeof(PowerBiServiceApi));
var mvcBuilder = services.AddControllersWithViews(options => {
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
mvcBuilder.AddMicrosoftIdentityUI();
services.AddSession();
}
应用设置.json
{
"AzureAd": {
"BaseUrl": "https://localhost:44358/",
"Instance": "https://login.microsoftonline.com/",
"Domain": "mycompany.onmicrosoft.com",
"TenantId": "xxx",
"ClientId": "xxx",
"ClientSecret": "xxx",
"CallbackPath": "/signin-oidc",
"SignedOutCallbackPath": "/signout-callback-oidc"
},
"PowerBi": {
"ServiceRootUrl": "https://api.powerbi.com/"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
PowerBiServiceApi.cs
using Microsoft.Extensions.Configuration;
using Microsoft.Identity.Web;
using Microsoft.PowerBI.Api;
using Microsoft.Rest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyCompany.UI.Extensions
{
public class EmbeddedReportViewModel
{
public string Id;
public string Name;
public string EmbedUrl;
public string Token;
}
public class PowerBiServiceApi
{
private ITokenAcquisition tokenAcquisition { get; }
private string urlPowerBiServiceApiRoot { get; }
public PowerBiServiceApi(IConfiguration configuration, ITokenAcquisition tokenAcquisition)
{
this.urlPowerBiServiceApiRoot = configuration["PowerBi:ServiceRootUrl"];
this.tokenAcquisition = tokenAcquisition;
}
public static readonly string[] RequiredScopes = new string[] {
"https://analysis.windows.net/powerbi/api/Report.Read.All"
};
// A method to get the Azure AD token (also known as 'access token')
public string GetAccessToken()
{
return this.tokenAcquisition.GetAccessTokenForUserAsync(RequiredScopes).Result;
}
public PowerBIClient GetPowerBiClient()
{
var tokenCredentials = new TokenCredentials(GetAccessToken(), "Bearer");
return new PowerBIClient(new Uri(urlPowerBiServiceApiRoot), tokenCredentials);
}
public async Task<EmbeddedReportViewModel> GetReport(Guid WorkspaceId, Guid ReportId)
{
PowerBIClient pbiClient = GetPowerBiClient();
// Call the Power BI Service API to get embedding data
var report = await pbiClient.Reports.GetReportInGroupAsync(WorkspaceId, ReportId);
// Return report embedding data to caller
return new EmbeddedReportViewModel
{
Id = report.Id.ToString(),
EmbedUrl = report.EmbedUrl,
Name = report.Name,
Token = GetAccessToken()
};
}
}
}
当我运行应用程序时,身份验证工作,然后当我尝试访问 PowerBi 报告时,它给了我以下错误:
AggregateException:发生一个或多个错误。(IDW10502:由于对用户的挑战而引发了 MsalUiRequiredException。请参阅https://aka.ms/ms-id-web/ca_incremental-consent。)
根据我的阅读,这是预期的行为,最好的解决方法是定义访问此外部 API 的范围或不使用内存令牌缓存。
家庭控制器.cs
public async Task<IActionResult> PowerBi()
{
Guid workspaceId = new Guid("xxx");
Guid reportId = new Guid("xxx");
var viewModel = await _powerBiServiceApi.GetReport(workspaceId, reportId);
return View(viewModel);
}
阅读文档后,我发现使用授权范围装饰控制器操作允许我访问报告:
HomeController.cs [已修改]
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public async Task<IActionResult> PowerBi()
{
Guid workspaceId = new Guid("xxx");
Guid reportId = new Guid("xxx");
var viewModel = await _powerBiServiceApi.GetReport(workspaceId, reportId);
return View(viewModel);
}
我可以在其他地方定义这个范围吗?这是最好的方法吗?我真的可以使用一些关于最佳方法的指导,因为我更喜欢在控制器之外为这样的事情提供逻辑。
解决方案
推荐阅读
- python - 如何使正则表达式方法超时?
- installation - 在网络上安装链码时出错
- php - 如何截断卡片
- arrays - VBA Excel 使用数组元素引用 Word 文档表格中的单元格
- amazon-web-services - 从 lambda 事件或上下文中动态检索 SQS 队列 URL
- raspberry-pi - 树莓派相机卡死
- java - JPQL/HQL。如何使用 Set 的过滤器查询具有 Set 的 @OneToMany 字段的实体 A ?
- c# - 如何将参数传递给 .NET 5 中的作用域服务?
- javascript - 在 React 中映射数组中每个对象的数组
- c# - 在 WPF 中更改子属性时如何引发 PropertyChangedEventHandler?