在ASP.Net核心网站中嵌入Power BI报告

Cha*_*uys 6 azure azure-active-directory powerbi asp.net-core

我有一个ASP.Net核心1.1网站,我想将电源BI报告嵌入到网站中.

Azure托管数据文档:https://powerbi.microsoft.com/en-us/documentation/powerbi-developer-embed-sample-app-owns-data/

使用https://github.com/Microsoft/PowerBI-Developer-Samples上App Owns Data样本,我有一个使用该样本的嵌入式报告解决方案.但是,示例项目正在.Net Framework 4.5.2上运行,当尝试将解决方案迁移到我的.Net核心应用程序时,我已迁移了代码,但.Net Core中的ActiveDirectorylibrary(Microsoft.IdentityModel.Clients.ActiveDirectorylibrary)没有包含UserPasswordCredential的方法

        var credential = new UserPasswordCredential(Username, Password);
Run Code Online (Sandbox Code Playgroud)

我发现在线推荐用于ASP.Net核心的解决方案是使用标签助手,但是现在Power BI嵌入式和Power BI服务已经与Power BI Premium的新产品融合了我不认为这个解决方案是可行的,因为对App Hosted数据的令牌认证的依赖性.

完整报告控制器方法:

            public class ReportController : Controller
    {
        private static readonly string Username = ConfigurationManager.AppSettings["pbiUsername"];
        private static readonly string Password = ConfigurationManager.AppSettings["pbiPassword"];
        private static readonly string AuthorityUrl = ConfigurationManager.AppSettings["authorityUrl"];
        private static readonly string ResourceUrl = ConfigurationManager.AppSettings["resourceUrl"];
        private static readonly string ClientId = ConfigurationManager.AppSettings["clientId"];
        private static readonly string ApiUrl = ConfigurationManager.AppSettings["apiUrl"];
        private static readonly string GroupId = ConfigurationManager.AppSettings["groupId"];

    public async Task<ActionResult> EmbedReport()
    {
        // Create a user password cradentials.
        var credential = new UserPasswordCredential(Username, Password);

        // Authenticate using created credentials
        var authenticationContext = new AuthenticationContext(AuthorityUrl);
        var authenticationResult = await authenticationContext.AcquireTokenAsync(ResourceUrl, ClientId, credential);

        if (authenticationResult == null)
        {
            return View(new EmbedConfig()
            {
                ErrorMessage = "Authentication Failed."
            });
        }

        var tokenCredentials = new TokenCredentials(authenticationResult.AccessToken, "Bearer");

        // Create a Power BI Client object. It will be used to call Power BI APIs.
        using (var client = new PowerBIClient(new Uri(ApiUrl), tokenCredentials))
        {
            // Get a list of reports.
            var reports = await client.Reports.GetReportsInGroupAsync(GroupId);

            // Get the first report in the group.
            var report = reports.Value.FirstOrDefault();

            if (report == null)
            {
                return View(new EmbedConfig()
                {
                    ErrorMessage = "Group has no reports."
                });
            }

            // Generate Embed Token.
            var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
            var tokenResponse = await client.Reports.GenerateTokenInGroupAsync(GroupId, report.Id, generateTokenRequestParameters);

            if (tokenResponse == null)
            {
                return View(new EmbedConfig()
                {
                    ErrorMessage = "Failed to generate embed token."
                });
            }

            // Generate Embed Configuration.
            var embedConfig = new EmbedConfig()
            {
                EmbedToken = tokenResponse,
                EmbedUrl = report.EmbedUrl,
                Id = report.Id
            };

            return View(embedConfig);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试过的:

在.Net Core项目中添加对.Net Framework 4.6.1的引用以公开.Net Framework并允许使用.Net等效的IdentityModel.Clients.ActiveDirectory,但似乎没有帮助.

如何修复库问题并嵌入.Net核心?

编辑 - 答案

根据@Fei Xue提供的答案,我编写了一个HTTP辅助类,它向API执行了一个帖子.基于返回的JSON,我创建了一个对象并使用了现在可用的身份验证令牌

助手班级:

  #region Settings

    public static string BaseUrl
    {
        get
        {
            return "https://login.microsoftonline.com/common/oauth2/token";
        }
    }

    #endregion

    public static async Task<HttpResponseMessage> MakeAsyncRequest(string url, Dictionary<string, string> content)
    {
        var httpClient = new HttpClient
        {
            Timeout = new TimeSpan(0, 5, 0),
            BaseAddress = new Uri(url)
        };

        httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type: application/x-www-form-urlencoded", "application/json");

        if (content == null)
        {
            content = new Dictionary<string, string>();
        }

        var encodedContent = new FormUrlEncodedContent(content);

        var result = await httpClient.PostAsync(httpClient.BaseAddress, encodedContent);

        return result;
    }
Run Code Online (Sandbox Code Playgroud)

宾语:

 public class AAD
{
    public string token_type { get; set; }
    public string scope { get; set; }
    public string expires_in { get; set; }
    public string ext_expires_in { get; set; }
    public string expires_on { get; set; }
    public string not_before { get; set; }
    public string resource { get; set; }
    public string access_token { get; set; }
    public string refresh_token { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

来自控制器的呼叫:

            var url = APIHelper.BaseUrl;
        var content = new Dictionary<string, string>();
        content["grant_type"] = "password";
        content["resource"] = "https://analysis.windows.net/powerbi/api";
        content["username"] = "<username>";
        content["password"] = "<password>";
        content["client_id"] = "<clientid>";

        var response = await APIHelper.MakeAsyncRequest(url, content);
        var result = response.Content.ReadAsStringAsync().Result;
        var AAD = JsonConvert.DeserializeObject<AAD>(result);
Run Code Online (Sandbox Code Playgroud)

Fei*_*SFT 10

Active Directory身份验证库的.Net核心不支持资源所有者密码凭据流.

作为一种变通方法,您可以直接撰写HTTP请求.以下是供您参考的示例:

POST https://login.microsoftonline.com/{tenant}/oauth2/token 
Content-Type: application/x-www-form-urlencoded

grant_type=password
&resource={resource}
&username={username}
&password={password}
&client_id={clientid}
&client_secret={client_secret}//if it is confidential app
Run Code Online (Sandbox Code Playgroud)