使用用户上下文/用户令牌 C# 调用Microsoft图形 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();

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

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

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

如果您遵循上面列出的示例,那么您就走在正确的轨道上。本教程演示如何代表登录用户调用 Graph/me 终结点Microsoft。在此示例中,本教程的Microsoft.Identity.Web部分中封装了 ASP.NET Core 中间件和 MSAL.Net 的复杂性。

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

然后,继续按照教程进行操作,使 MSAL 能够挂接到 OpenID Connect 事件并兑换由 ASP.NET Core 中间件获取的授权代码。收到令牌后,MSAL 会将其保存到令牌缓存中(也有这方面的教程(。

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

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

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

注意:您需要使用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);
}
}

然后,您将需要一个模型来处理来自Web请求的响应

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

然后,您将需要一个函数来从Web请求中提取数据

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

非常重要:您还必须确保对活动目录应用程序注册具有适当的 api 权限。如果没有它,您只会从图形 API 获得请求被拒绝响应。

希望这有帮助。

如果要以登录用户身份运行图形命令,则实际上不需要访问令牌即可在 C# 中运行图形命令。在启动.cs文件(或程序.cs(中,应具有以下行:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();

然后,在应用程序注册中,转到 API 权限(如其他人所述(,并为要访问的每个项设置Microsoft Graph 的委派权限。例如,委派的权限表示 SharePoint 中登录用户的权限。这意味着,如果运行命令来选择库中的文档,则该用户需要有权访问该网站和库,以便您返回代码中的任何文档。

从那里,您应该能够运行以下代码:

GraphServiceClient _graphServiceClient = new GraphServiceClient();
var currentUser = await _graphServiceClient.Me.Request().GetAsync();

我构建了一个 GraphHelper 类,并在构造函数方法中传入了 GraphServiceClient。调用帮助程序类的控制器也接收 GraphServiceClient,然后将其直接传递给帮助程序。在我的代码中,我从未真正"新建"客户端,但它工作得很好。

关于这种方法的一个注意事项。执行此操作时,都需要在 Azure AD 中定义应用角色和用户。你将无法使用标识管理方法,其中身份验证通过 Azure 进行,但授权发生在本地数据库中,其中有 AspNetRoles、AspNetUsers 等表。我遇到了这个问题,这导致我走向另一个方向。但是,如果你可以管理Azure中的所有内容,你应该没问题。

最新更新