如何使用 MSAL 获取访问令牌以代表控制台应用程序中的用户调用 MS Graph?

FIL*_*FIL 7 c# azure-active-directory azure-ad-msal microsoft-graph-api

我有一个 SPA 应用程序,它使用 AAD v2 身份验证与我的后端 Web API 进行通信。现在,我正在开发一个控制台应用程序来代表登录到 SPA 应用程序的用户调用 Microsoft Graph。

我有用户的有效访问令牌(用于调用后端 Web API)。我想使用此访问令牌来请求用于访问 MS Graph 的新令牌。

以下是使用 MSAL.NET 请求具有 MS Graph 范围的新访问令牌的控制台应用程序的代码:

string clientId = "<clientId>";
string clientSecret = "<clientSecret>";
string accessToken = "<validAccessTokenForWebApi>";
string assertionType = "urn:ietf:params:oauth:grant-type:jwt-bearer";
string[] scopes = new string[] { "User.Read", "Mail.Send" };
string graphAccessToken = null;

try
{
    var app = ConfidentialClientApplicationBuilder
                .Create(clientId).WithClientSecret(clientSecret).Build();

    var userAssertion = new UserAssertion(accessToken, assertionType);

    var result = app.AcquireTokenOnBehalfOf(scopes, userAssertion)
                    .ExecuteAsync().GetAwaiter().GetResult();

    graphAccessToken = result.AccessToken;
}
catch (MsalServiceException ex)
{
    throw;
}
Run Code Online (Sandbox Code Playgroud)

但当我打电话时,app.AcquireTokenOnBehalfOf()我得到一个例外:

AADSTS50013:断言签名验证失败。[原因 - 提供的签名值与预期签名值不匹配。,客户端使用的密钥指纹:'BB839F3453C7C04068B078EDADAB8E6D5F382E76',找到密钥'Start=06/04/2019 00:00:00,End=06/04/2021 00:00:00']

是什么原因?代表用户获取访问令牌的正确方法是什么?

更新 - 为什么我需要控制台应用程序?

我可以直接从后端 API 调用 Graph API,但某些操作可能会被用户延迟(例如 30 分钟后使用 Graph API 发送邮件)。这就是为什么我需要使用按计划运行的控制台应用程序来执行此操作。

Jim*_* Xu 2

如果你想使用OAuth 2.0 On-Behalf-Of flow,我认为你不需要开发一个控制台应用程序来调用graph api。您可以直接使用后端 Web API 应用程序获取访问令牌,然后调用 Microsoft Graph。根据我的理解,你只需执行以下步骤

  1. 在客户端应用程序中登录用户
  2. 获取 Web API (TodoListService) 的令牌并调用它。
  3. 然后,Web API 调用另一个下游 Web API(Microsoft Graph)。

在此输入图像描述

欲了解更多详情,请参阅示例

关于如何在控制台应用程序中通过代表流获取访问令牌,详细步骤如下。

注册 Web api 应用程序

  1. 注册APP
  2. 创建客户端机密
  3. 配置访问Graph API的权限
  4. 配置应用程序以公开 Web API(添加 api 的范围)

注册 SAP 应用程序

  1. 注册APP
  2. 创建客户端机密
  3. 配置访问Web API的权限

为 Web API 应用程序配置已知客户端应用程序

  1. 在 Azure 门户中,导航到 Web api 应用程序注册,然后单击“清单”部分。

  2. 查找属性knownClientApplications并添加SAP应用程序的客户端ID

获取访问令牌以调用 Web api

   GET https://login.microsoftonline.com/common/oauth2/v2.0/authorize
?scope=<you web api scope> openid
    &redirect_uri=<your sap app redirect url>
    &nonce=test123
    &client_id=<you sap app client id>
    &response_type=id_token token
Run Code Online (Sandbox Code Playgroud)

使用代表流程获取访问令牌

休息API

POST https://login.microsoftonline.com/common/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&client_id=<you web api client id>
&assertion=<you acess token you get in above steps>
&client_secret=<you app secret> 
&scope=https://graph.microsoft.com/user.read
&requested_token_use=on_behalf_of
Run Code Online (Sandbox Code Playgroud)

MSAL.net 代码

string[] scopes = { "user.read" };
            string accesstoken = "";

            string appKey = "yor web api client secret";
            string clientId = "your web api application id";

            var app = ConfidentialClientApplicationBuilder.Create(clientId)
              .WithClientSecret(appKey)
              .Build();
            UserAssertion userAssertion = new UserAssertion(accesstoken, 
 "urn:ietf:params:oauth:grant-type:jwt-bearer");
            var result = app.AcquireTokenOnBehalfOf(scopes, userAssertion).ExecuteAsync().Result;
            Console.WriteLine(result.AccessToken);
Run Code Online (Sandbox Code Playgroud)