首页 > 解决方案 > 从我的 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);
}

我可以在其他地方定义这个范围吗?这是最好的方法吗?我真的可以使用一些关于最佳方法的指导,因为我更喜欢在控制器之外为这样的事情提供逻辑。

标签: c#asp.net-corepowerbiasp.net-identity

解决方案


推荐阅读