使用用户上下文/用户令牌 C# 调用 Microsoft Graph API

use*_*911 5 c# azure-ad-msal microsoft-graph-sdks microsoft-graph-api

我有一个 Web 应用程序,其中用户使用本示例中定义的方法登录。

现在我想为此用户调用 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();
Run Code Online (Sandbox Code Playgroud)

根据本文档,我需要使用机密客户端流程,但我不确定是否需要使用授权代码流程或代表。由于我在这里遵循的方法,无法访问授权代码。

ConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantId)
    .WithCertificate(clientCertificate)
    .Build();
Run Code Online (Sandbox Code Playgroud)

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

Jef*_*eff 3

注意:您需要使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你需要一个模型来处理网络请求的响应

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

    [JsonProperty("access_token")]
    public string AccessToken { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

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);
}
Run Code Online (Sandbox Code Playgroud)

然后请求经过身份验证的图形 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

非常重要:您还必须确保您在 Active Directory 应用程序注册上拥有适当的 api 权限。如果没有它,您将只能从图形 API 获得请求被拒绝的响应。

希望这可以帮助。

  • Jeff,请使用这些库,而不是针对 ASP.NET / ASP.NET Core 应用程序的协议进行编码。有很多事情需要考虑,这使得直接协议方法不安全。此外,像 MSAL 这样的库将缓存令牌、保留刷新令牌等...... (2认同)