【问题标题】:Calling Microsoft Graph API using user context/user token C#使用用户上下文/用户令牌 C# 调用 Microsoft Graph API
【发布时间】:2020-05-27 11:47:11
【问题描述】:

我有一个 Web 应用程序,其中用户使用定义的方法in this sample 登录。

现在我想为此用户调用 Microsoft Graph。我浏览了许多文件,这应该如何完成非常令人困惑。这是我尝试过的。我不确定如何获取该用户的访问令牌。

//not sure about this
var token = await GetAccessToken();

var client = new GraphServiceClient(
    new DelegateAuthenticationProvider(
        requestMessage =>
        {
            requestMessage.Headers.Authorization =
                new AuthenticationHeaderValue("Bearer", token);

            return Task.FromResult(0);
        }));

var result = await client
    .Me
    .Request()
    .GetAsync();

根据this documentation,我需要使用机密客户端流程,但我不确定是否需要使用授权码流程或代表。由于I followed here 的方法,我无法访问授权码。

ConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantId)
    .WithCertificate(clientCertificate)
    .Build();

有人可以指导我如何获取用户的访问令牌吗?我应该使用授权码流还是代表?

【问题讨论】:

    标签: c# microsoft-graph-api msal microsoft-graph-sdks


    【解决方案1】:

    如果您关注上面列出的sample,那么您就在正确的轨道上。按照教程,它显示了如何代表登录用户调用 Microsoft Graph /me 端点。在本示例中,ASP.NET Core 中间件和 MSAL.Net 的复杂性封装在教程的Microsoft.Identity.Web 部分。

    您应该已经在 Azure 门户中注册了一个 Web 应用。现在您将调用 Microsoft Graph,您需要为 Web 应用注册证书或密码。然后在 API 权限中,确保选择了 Microsoft API 选项卡并选择您想要用于 Microsoft Graph 的选项卡。

    然后,继续关注tutorial 以使 MSAL 能够连接到 OpenID Connect 事件并兑换 ASP.NET Core 中间件获得的授权代码。收到令牌后,MSAL 会将其保存到令牌缓存中(也有教程)。

    继续按照教程进行操作,您将添加返回 GraphServiceClientGraphServiceClientFactory.cs。当它收到 Microsoft Graph 的访问令牌时,它将向 Graph 发出请求,并在标头中发送访问令牌。代码是here

    public async Task AuthenticateRequestAsync(HttpRequestMessage request)
    {
          string accessToken = await acquireAccessToken.Invoke();
    
          // Append the access token to the request.
          request.Headers.Authorization = new AuthenticationHeaderValue(
          Infrastructure.Constants.BearerAuthorizationScheme, 
          accessToken);
    }
    

    还有一些设置要做,但按照教程进行操作,您应该能够获取令牌,然后使用它来调用 Microsoft Graph。

    【讨论】:

      【解决方案2】:

      注意:您需要使用 Microsoft.Graph

      引用您的项目

      首先,您需要一个函数来请求访问令牌

      async Task<string> Post(string uri, Dictionary<string, string> parameters)
      {
          HttpResponseMessage response = null;
          try
          {
              using (var httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(30) })
              {
                  response = await httpClient.PostAsync(uri, new FormUrlEncodedContent(parameters));
                  if (!response.IsSuccessStatusCode)
                      throw new Exception("post request failed.");
      
                  var content = response.Content.ReadAsStringAsync().Result;
                  if (string.IsNullOrWhiteSpace(content))
                      throw new Exception("empty response received.");
      
                  return content;
              }
          }
          catch (Exception e)
          {
              throw new Exception(error);
          }
      }
      

      那么你需要一个模型来处理来自网络请求的响应

      public class TokenRequest
      {
          [JsonProperty("token_type")]
          public string TokenType { get; set; }
      
          [JsonProperty("access_token")]
          public string AccessToken { get; set; }
      }
      

      然后你需要一个函数来从网络请求中提取数据

      TokenRequest GetAccessToken()
      {
          // request for access token.
          var parameters = new Dictionary<string, string>();
          parameters.Add("client_id", "YOUR CLIENT ID");
          parameters.Add("client_secret", "YOUR CLIENT SECRET");
          parameters.Add("scope", "https://graph.microsoft.com/.default");
          parameters.Add("grant_type", "client_credentials");
      
          var response = Post(
              $"https://login.microsoftonline.com/{YOUR TENANT ID}/oauth2/v2.0/token",
              parameters).Result;
      
          return JsonConvert.DeserializeObject<TokenRequest>(response);
      }
      

      然后请求一个经过身份验证的图形 api 客户端

      GraphServiceClient GetClient()
      {
          var tokenRequest = GetAccessToken();
          var graphClient = new GraphServiceClient(
              new DelegateAuthenticationProvider(
                  async (requestMessage) => {
                      await Task.Run(() => {
                          requestMessage.Headers.Authorization = new AuthenticationHeaderValue(
                              tokenRequest.TokenType,
                              tokenRequest.AccessToken);
      
                          requestMessage.Headers.Add("Prefer", "outlook.timezone=\"" + TimeZoneInfo.Local.Id + "\"");
                      });
                  }));
      
          return graphClient;
      }
      

      然后使用客户端,您现在可以执行查询

      var graphClient = GetClient();
      var user = await graphClient
          .Users["SOME EMAIL ADDRESS HERE"]
          .Request()
          .GetAsync();
      

      非常重要:您还必须确保您对 Active Directory 应用程序注册具有适当的 api 权限。没有它,你只会得到来自 graph api 的 request denied 响应。

      希望这会有所帮助。

      【讨论】:

      • Jeff,请宁愿使用库而不是针对 ASP.NET / ASP.NET Core 应用程序的协议进行编码。有很多事情需要考虑,这使得直接到协议的方法不安全。像 MSAL 这样的库也会缓存令牌,保持刷新令牌等......
      • 嗨,杰夫,我有 WebAPI 项目,我添加了你的代码,它生成的 Access_Token 不起作用,如果我用我在 Postman 中生成的替换它就可以了。 Postman 和您的代码使用相同的 client_id、client_secret 和tenantId。任何想法为什么会这样?谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      • 2015-09-12
      相关资源
      最近更新 更多