在ASP.Net Core网站中嵌入Power BI报表

7
我有一个ASP.Net core 1.1网站,希望将Power 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 Core应用程序时,我已经迁移了代码,但是在.Net Core中的ActiveDirectorylibrary(Microsoft.IdentityModel.Clients.ActiveDirectorylibrary)不包含UserPasswordCredential方法。
        var credential = new UserPasswordCredential(Username, Password);

我发现在线推荐的ASP.Net Core解决方案是使用标签助手,然而现在随着Power BI Embedded和Power BI服务与新的Power BI Premium的融合,我认为由于对应用主机数据的令牌身份验证的依赖关系,这种解决方案可能不再可行。
完整的报告控制器方法:
            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);
        }
    }
}

我尝试过的方法:

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

我该如何解决库问题并嵌入到.Net Core中?

修改 - 答案

基于@Fei Xue提供的答案,我编写了一个HTTP辅助类,执行对API的post。根据返回的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;
    }

对象:

 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; }
}

控制器调用:

            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);

你能否请提供你的完整最终控制器代码?我正在尝试做同样的事情 - 你的工作非常出色,但我认为我可能漏掉了一两个部分。 - toy
1
@toy,对于延迟的回复表示歉意。很不幸,我不认为我还有源代码了,需要查看我的存档并回复您。 - Chad Bonthuys
没关系 - 我发现缺失的部分是端点已经从原始代码(即,你之前的那些东西)更改了,我没有注意到,但现在一切都好了 - 谢谢。 - toy
看看这篇文章:使用ASP.NET Core嵌入Power BI报告 - Dmitry Pavlov
4个回答

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

3

不确定还有多少人在适应 PowerBI 嵌入式 App-Owns-Data 示例代码到 .Net Core 的问题上遇到困难,但是我通过将 Chad 的示例类与 PowerBI社区帖子中的代码 融合成功地使其运行起来。

关键(至少对我而言)是按照 PowerBI 帖子中的建议替换原始示例中的此代码:

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

使用这个位(AAD是Chad示例返回的对象):
var authenticationResult = AAD;

以下是完整控制器代码,还提供了实际的嵌入令牌,无需调用UserPasswordCredential。希望它能为其他人节省几个小时的挖掘时间。感谢Chad和Fei Xue提供样例!干杯。

public class DashboardController : Controller
{

    private static readonly string Username = "yourUN";
    private static readonly string Password = "yourPW";
    private static readonly string AuthorityUrl = "https://login.windows.net/common/oauth2/authorize/";
    private static readonly string ResourceUrl = "https://analysis.windows.net/powerbi/api";
    private static readonly string ClientId = "yourClientId";
    private static readonly string ApiUrl = "https://api.powerbi.com";
    private static readonly string GroupId = "yourGroupId";
    private static readonly string ReportId = "yourReportId";


    public class APIHelper 
    {
        #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;
        }    
    }


    public class AAD
    {
        [JsonProperty("token_type")]
        public string TokenType { get; set; }
        [JsonProperty("scope")]
        public string Scope { get; set; }
        [JsonProperty("experies_in")]
        public int ExpiresIn { get; set; }
        [JsonProperty("ext_experies_in")]
        public int ExtExpiresIn { get; set; }
        [JsonProperty("experies_on")]
        public int ExpiresOn { get; set; }
        [JsonProperty("not_before")]
        public int NotBefore { get; set; }
        [JsonProperty("resource")]
        public Uri Resource { get; set; }
        [JsonProperty("access_token")]
        public string AccessToken { get; set; }
        [JsonProperty("refresh_token")]
        public string RefreshToken { get; set; }
    }




    public async Task<ActionResult> Index(string username, string roles)
    {
        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 tokenresult = response.Content.ReadAsStringAsync().Result;
        var AAD = JsonConvert.DeserializeObject<AAD>(tokenresult);

        var result = new EmbedConfig();
        try
        {
            result = new EmbedConfig { Username = username, Roles = roles };
            var error = GetWebConfigErrors();
            if (error != null)
            {
                result.ErrorMessage = error;

                return View(result);
            }

            // Create a user password cradentials.
            var authenticationResult = AAD;

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

            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);

                Report report;
                if (string.IsNullOrEmpty(ReportId))
                {
                    // Get the first report in the group.
                    report = reports.Value.FirstOrDefault();
                }

                else
                {
                    report = reports.Value.FirstOrDefault(r => r.Id == "3a447f03-ad31-4e78-a3f1-2a6c008fcd8e");
                }

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

                var datasets = await client.Datasets.GetDatasetByIdInGroupAsync(GroupId, report.DatasetId);
                result.IsEffectiveIdentityRequired = datasets.IsEffectiveIdentityRequired;
                result.IsEffectiveIdentityRolesRequired = datasets.IsEffectiveIdentityRolesRequired;
                GenerateTokenRequest generateTokenRequestParameters;
                // This is how you create embed token with effective identities

                generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");



                var tokenResponse = await client.Reports.GenerateTokenInGroupAsync(GroupId, report.Id, generateTokenRequestParameters);

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

                // Generate Embed Configuration.
                result.EmbedToken = tokenResponse;
                result.EmbedUrl = report.EmbedUrl;
                result.Id = report.Id;

                return View(result);

            }
        }
        catch (HttpOperationException exc)

        {
            result.ErrorMessage = string.Format("Status: {0} for ID: ({1})\r\nResponse: {2}\r\nRequestId: {3}", exc.Response.StatusCode, (int)exc.Response.StatusCode, exc.Response.Content, exc.Response.Headers["RequestId"].FirstOrDefault());
        }
        catch (Exception exc)
        {
            result.ErrorMessage = exc.ToString();
        }

        return View(result);

    }
}

我正在使用您的示例,但出现了一个错误,提示“invalid_grant - Invalid username and password”,尽管它是正确的。您有任何想法为什么会发生这种情况吗? - MAK
嗨MAK,只是想澄清一下,您是否编辑了信息静态只读字符串以反映您的PowerBI帐户信息?另外,为了明确起见,您最好实现一种方法来引用此信息,以避免在实际代码中使用敏感数据。 - HunterTheGatherer
是的,我已经在我的代码中替换了这些值。同时,我将为敏感数据采用不同的策略。 - MAK
1
@MAK 可能已经太晚了,但我遇到了同样的问题,并最终确定是由于 ADFS 导致的。我在本主题上发布了一个对我有效的解决方案。 - tpankake
谢谢@tpankake,我正在尝试重新创建问题,但是现在遇到了困难(原始代码库上的PowerBI帐户已不再链接)。干杯。 - HunterTheGatherer

2
我尝试了这里和其他一些在线获取aspnetcore嵌入令牌的解决方案。我一直收到无效的用户名/密码提示,但我发现如果我使用微软提供的.NET Framework示例,一切都运行得非常顺利。

https://github.com/Microsoft/PowerBI-Developer-Samples/tree/master/App%20Owns%20Data/PowerBIEmbedded_AppOwnsData

所以,我知道我的凭据是正确的。最终,我在本地运行了.NET Framework解决方案,并使用Fiddler观察了我的出站流量。我能够看到由于我在联合式AD租户(ADFS)上,还有其他的交换发生。我从那里开始倒推,得出了以下(有效的)代码。希望它能帮助某些人 -
public class PowerBIAuthenticator
{
    private static OAuthResult _cachedResult = null;

    private PowerBIOptions _powerBIOptions;
    private ILogger<PowerBIAuthenticator> _logger;

    public PowerBIAuthenticator()
    {
        _powerBIOptions = new PowerBIOptions();
        _powerBIOptions.ResourceUrl = "https://analysis.windows.net/powerbi/api";
        _powerBIOptions.AuthorityUrl = "https://login.windows.net/common/oauth2/token";
        _powerBIOptions.ApiUrl = "https://api.powerbi.com/";
        _powerBIOptions.ClientId = "azure-ad-client-id-here";
        _powerBIOptions.Username = "master-account-username-here";
        _powerBIOptions.Password = "master-account-password-here";
    }

    public async Task<OAuthResult> AuthenticateAsync(PowerBISecureOptions secureOptions)
    {
        if (_cachedResult != null)
        {
            var expireDateTime = DateTimeOffset.FromUnixTimeSeconds(_cachedResult.ExpiresOn);
            var currentDateTime = DateTimeOffset.Now.UtcDateTime;

            if (currentDateTime < expireDateTime)
            {
                return _cachedResult;
            }
        }

        OAuthResult authToken = await this.GetAuthToken();
        _cachedResult = authToken;

        return authToken;
    }

    private async Task<OAuthResult> GetAuthToken() 
    {
        string commonRequestGuid = Guid.NewGuid().ToString();
        OAuthResult oauthResult = null;

        UserRealm userRealm = await this.GetUserRealm(commonRequestGuid);
        if (userRealm.account_type.Equals("Federated"))
        {
            XmlDocument metadata
                = await this.GetFederationMetadata(commonRequestGuid, userRealm.federation_metadata_url);

            string trustBinding = GetFederatedUserTrustBinding(metadata);
            XmlDocument trustDocument
                = await this.GetFederatedUserTrust(commonRequestGuid, trustBinding);

            var userAssertionNodes = trustDocument.GetElementsByTagName("saml:Assertion");
            var userAssertionNode = userAssertionNodes[0].OuterXml;

            using (var client = new HttpClient())
            {
                string tokenUri = "https://login.windows.net/common/oauth2/token";
                var ua = new UserAssertion(
                    userAssertionNode,
                    "urn:ietf:params:oauth:grant-type:saml1_1-bearer",
                    Uri.EscapeDataString(_powerBIOptions.Username));

                UTF8Encoding encoding = new UTF8Encoding();
                Byte[] byteSource = encoding.GetBytes(ua.Assertion);
                string base64ua = Convert.ToBase64String(byteSource);

                var tokenForm = new FormUrlEncodedContent(new[]
                {
                    new KeyValuePair<string, string>("resource", _powerBIOptions.ResourceUrl),
                    new KeyValuePair<string, string>("client_id", _powerBIOptions.ClientId),
                    new KeyValuePair<string, string>("grant_type", "urn:ietf:params:oauth:grant-type:saml1_1-bearer"),
                    new KeyValuePair<string, string>("assertion", base64ua),
                    new KeyValuePair<string, string>("scope", "openid"),
                });

                var tokenResult = await client.PostAsync(tokenUri, tokenForm);
                var tokenContent = await tokenResult.Content.ReadAsStringAsync();

                oauthResult = JsonConvert.DeserializeObject<OAuthResult>(tokenContent);
            }
        }
        else
        {
            using (var client = new HttpClient())
            {
                var result = await client.PostAsync(_powerBIOptions.AuthorityUrl, new FormUrlEncodedContent(new[]
                {
                    new KeyValuePair<string, string>("resource", _powerBIOptions.ResourceUrl),
                    new KeyValuePair<string, string>("client_id", _powerBIOptions.ClientId),
                    new KeyValuePair<string, string>("grant_type", "password"),
                    new KeyValuePair<string, string>("username", _powerBIOptions.Username),
                    new KeyValuePair<string, string>("password", _powerBIOptions.Password),
                    new KeyValuePair<string, string>("scope", "openid"),
                }));

                var tokenContent = await result.Content.ReadAsStringAsync();
                oauthResult = JsonConvert.DeserializeObject<OAuthResult>(tokenContent);
            }
        }
        return oauthResult;
    }

    private async Task<UserRealm> GetUserRealm(string commonRequestGuid)
    {
        UserRealm userRealm = new UserRealm();

        using (var client = new HttpClient())
        {
            string userRealmUri = $"https://login.windows.net/common/UserRealm/{_powerBIOptions.Username}?api-version=1.0";

            HttpRequestMessage realmRequest = new HttpRequestMessage(HttpMethod.Get, userRealmUri);
            realmRequest.Headers.Add("Accept", "application/json");
            realmRequest.Headers.Add("return-client-request-id", "true");
            realmRequest.Headers.Add("client-request-id", commonRequestGuid);

            HttpResponseMessage realmResponse = client.SendAsync(realmRequest).Result;
            string realmString = await realmResponse.Content.ReadAsStringAsync();

            userRealm = JsonConvert.DeserializeObject<UserRealm>(realmString);
        }
        return userRealm;
    }

    private async Task<XmlDocument> GetFederationMetadata(string commonRequestGuid, string adfsMetadataUri) 
    {
        string metadataString = string.Empty;

        using (var client = new HttpClient())
        {
            HttpRequestMessage metadataRequest = new HttpRequestMessage(HttpMethod.Get, adfsMetadataUri);
            metadataRequest.Headers.Add("Accept", "application/json");
            metadataRequest.Headers.Add("return-client-request-id", "true");
            metadataRequest.Headers.Add("client-request-id", commonRequestGuid);

            HttpResponseMessage metadataResponse = client.SendAsync(metadataRequest).Result;
            metadataString = await metadataResponse.Content.ReadAsStringAsync();
        }

        XmlDocument metadataDoc = new XmlDocument();
        metadataDoc.LoadXml(metadataString);

        return metadataDoc;
    }

    private async Task<XmlDocument> GetFederatedUserTrust(string commonRequestGuid, string trustBindingUri)
    {
        string trustString = null;

        using (var client = new HttpClient())
        {
            HttpRequestMessage trustRequest = new HttpRequestMessage(HttpMethod.Post, trustBindingUri);
            trustRequest.Headers.Add("Accept", "application/json");
            trustRequest.Headers.Add("return-client-request-id", "true");
            trustRequest.Headers.Add("client-request-id", commonRequestGuid);
            trustRequest.Headers.Add("SOAPAction", "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue");

            DateTime now = DateTime.UtcNow;
            DateTime then = now.AddMinutes(10);

            string trustBody = __federatedUserTrustBody.
                Replace("{messageGuid}", Guid.NewGuid().ToString()).
                Replace("{adfsUserEndpoint}", trustBindingUri).
                Replace("{SecurityCreated}", now.ToString("o")).
                Replace("{SecurityExpires}", then.ToString("o")).
                Replace("{tokenGuid}", Guid.NewGuid().ToString()).
                Replace("{username}", _powerBIOptions.Username).
                Replace("{password}", _powerBIOptions.Password);

            trustRequest.Content = new StringContent(trustBody, Encoding.UTF8, "application/soap+xml");

            HttpResponseMessage userTrustResponse = client.SendAsync(trustRequest).Result;
            trustString = await userTrustResponse.Content.ReadAsStringAsync();
        }

        XmlDocument trustDocument = new XmlDocument();
        trustDocument.LoadXml(trustString);

        return trustDocument;
    }

    private string GetFederatedUserTrustBinding(XmlDocument metadata)
    {
        XmlNodeList services = metadata.GetElementsByTagName("wsdl:service");
        List<XmlNode> ports = new List<XmlNode>();
        foreach (XmlNode node in services[0])
        {
            if (node.Name.Equals("wsdl:port"))
                ports.Add(node);
        }

        XmlNode trustPort = ports.FirstOrDefault(p => p.Attributes["name"] != null 
        && p.Attributes["name"].Value.Equals("UserNameWSTrustBinding_IWSTrust13Async"));

        XmlNode trustAddress = null;
        foreach (XmlNode node in trustPort.ChildNodes)
        {
            if (node.Name.Equals("soap12:address"))
            {
                trustAddress = node;
                break;
            }
        }

        return trustAddress.Attributes["location"].Value;
    }

    public class UserRealm
    {
        public string ver { get; set; }
        public string account_type { get; set; }
        public string domain_name { get; set; }
        public string federation_protocol { get; set; }
        public string federation_metadata_url { get; set; }
        public string federation_active_auth_url { get; set; }
        public string cloud_instance_name { get; set; }
        public string cloud_audience_urn { get; set; }
    }

    public class PowerBIOptions
    {
        [JsonProperty("resourceUrl")]
        public string ResourceUrl { get; set; }
        [JsonProperty("authorityUrl")]
        public string AuthorityUrl { get; set; }
        [JsonProperty("apiUrl")]
        public string ApiUrl { get; set; }
        [JsonProperty("clientId")]
        public string ClientId { get; set; }
        [JsonProperty("username")]
        public string Username { get; set; }
        [JsonProperty("password")]
        public string Password { get; set; }
    }

    public class OAuthResult
    {
        [JsonProperty("token_type")]
        public string TokenType { get; set; }
        [JsonProperty("scope")]
        public string Scope { get; set; }
        [JsonProperty("expires_in")]
        public int ExpiresIn { get; set; }
        [JsonProperty("ext_expires_in")]
        public int ExtExpiresIn { get; set; }
        [JsonProperty("expires_on")]
        public int ExpiresOn { get; set; }
        [JsonProperty("not_before")]
        public int NotBefore { get; set; }
        [JsonProperty("resource")]
        public Uri Resource { get; set; }
        [JsonProperty("access_token")]
        public string AccessToken { get; set; }
        [JsonProperty("refresh_token")]
        public string RefreshToken { get; set; }
    }

    private string __federatedUserTrustBody = 
        @"<s:Envelope xmlns:s='http://www.w3.org/2003/05/soap-envelope' xmlns:a='http://www.w3.org/2005/08/addressing' xmlns:u='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>
          <s:Header>
          <a:Action s:mustUnderstand='1'>http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
          <a:messageID>urn:uuid:{messageGuid}</a:messageID>
          <a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>
          <a:To s:mustUnderstand='1'>{adfsUserEndpoint}</a:To>
          <o:Security s:mustUnderstand='1' xmlns:o='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'><u:Timestamp u:Id='_0'><u:Created>{SecurityCreated}</u:Created><u:Expires>{SecurityExpires}</u:Expires></u:Timestamp><o:UsernameToken u:Id='uuid-{tokenGuid}'><o:Username>{username}</o:Username><o:Password>{password}</o:Password></o:UsernameToken></o:Security>
          </s:Header>
          <s:Body>
          <trust:RequestSecurityToken xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>
          <wsp:AppliesTo xmlns:wsp='http://schemas.xmlsoap.org/ws/2004/09/policy'>
          <a:EndpointReference>
          <a:Address>urn:federation:MicrosoftOnline</a:Address>
          </a:EndpointReference>
          </wsp:AppliesTo>
          <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
          <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
          </trust:RequestSecurityToken>
          </s:Body>
          </s:Envelope>";
}

0

我已经用以下代码片段解决了这个问题。你只需要替换你的PowerBI账户的用户名和密码,client_id、client_secret、authEndPoint,并创建AzureAdTokenResponseDto类。

    public static async Task<string> GetToken()
        {
            HttpClient client = new HttpClient();
            var content = new FormUrlEncodedContent(new[]
             {
      new KeyValuePair<string, string>("grant_type", "password"),
      new KeyValuePair<string, string>("username", "<user name>"),
      new KeyValuePair<string, string>("password", "<password>"),
      new KeyValuePair<string, string>("client_id", "<client_id>"),
      new KeyValuePair<string, string>("scope", "openid"),
      new KeyValuePair<string, string>("client_secret", "<client_secret>"),
      new KeyValuePair<string, string>("resource", "https://analysis.windows.net/powerbi/api")
   });
            HttpResponseMessage res = client.PostAsync("authEndPoint", content).Result;
            string json = await res.Content.ReadAsStringAsync();
            AzureAdTokenResponseDto tokenRes = JsonConvert.DeserializeObject<AzureAdTokenResponseDto>(json);
            return tokenRes.AccessToken;
        }

现在您需要创建AzureAdTokenResponseDto类,如下所示。
public class AzureAdTokenResponseDto
    {
        [JsonProperty("access_token")]
        public string AccessToken { get; set; }
    }

请确保安装了Newtonsoft.Json Nuget包。在ASP.NET Core中,它对我非常有效。

什么是理想的OAuth终端点? - TBA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接