Microsoft Graph 令牌不包含权限,或权限无法理解

Roe*_*and 8 c# oauth-2.0 office365 microsoft-graph-api

我正在使用 Microsoft Graph 并创建了一个应用程序来读取来自特定用户的邮件。

但是,在获得访问令牌并尝试读取邮件文件夹后,我收到了 401 未经授权的答复。详细信息是:

令牌不包含权限,或权限无法理解

这似乎是一个非常明确的信息,但不幸的是我无法找到解决方案。这是我到目前为止所做的:

权限是: 在此处输入图片说明 在此处输入图片说明 - 编写以下代码以获取访问令牌:

 // client_secret retrieved from secure storage (e.g. Key Vault)
 string tenant_id = "xxxx.onmicrosoft.com";
 ConfidentialClientApplication client = new ConfidentialClientApplication(
 "..",
 $"https://login.microsoftonline.com/{tenant_id}/",
 "https://dummy.example.com", // Not used, can be any valid URI 
 new ClientCredential(".."),
 null, // Not used for pure client credentials
 new TokenCache());
Run Code Online (Sandbox Code Playgroud)
   string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
   AuthenticationResult result = client.AcquireTokenForClientAsync(scopes).Result;
   string token = result.AccessToken;
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好。我确实得到了一个令牌。

现在我想阅读邮件文件夹:

url = "https://graph.microsoft.com/v1.0/users/{username}/mailFolders";
handler = (HttpWebRequest)WebRequest.Create(url);
handler.Method = "GET";
handler.ContentType = "application/json";
handler.Headers.Add("Authorization", "Bearer " + token);
response = (HttpWebResponse)handler.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
    returnValue = sr.ReadToEnd();
}
Run Code Online (Sandbox Code Playgroud)

这次我收到了 401 消息,其中包含详细信息:

令牌不包含权限,或者权限无法理解。

我在互联网上搜索过,但找不到我的令牌为什么没有权限的答案。

谢谢你的时间!

更新 1

如果我使用 Graph Explorer 读取邮件文件夹,则它工作正常。此外:如果我从我的浏览器中获取令牌 ID 在我的第二段代码中使用它,那么我也会得到一个结果。所以,问题实际上是我从第一步收到的令牌。

Phi*_*ret 5

为了确保其按照您的预期工作,您应该明确说明您希望为哪个租户获取访问令牌。(在此租户中,应用程序当然应该已经获得管理员同意。)

使用特定于租户的端点,而不是“通用”令牌端点:

string url = "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token";
Run Code Online (Sandbox Code Playgroud)

(其中{tenant-id}是租户的租户 ID(Guid)或任何经过验证的域名。)

我还强烈建议您不要自行构建令牌请求,正如您在问题中所示的那样。这对于教育目的可能有用,但从长远来看往往不安全且容易出错。

您可以使用各种库来代替。下面是使用适用于 .NET 的 Microsoft 身份验证库 (MSAL) 的示例:

// client_secret retrieved from secure storage (e.g. Key Vault)
string tenant_id = "contoso.onmicrosoft.com";
ConfidentialClientApplication client = new ConfidentialClientApplication(
    client_id,
    $"https://login.microsoftonline.com/{tenant_id}/",
    "https://dummy.example.com", // Not used, can be any valid URI 
    new ClientCredential(client_secret),
    null, // Not used for pure client credentials
    new TokenCache());

string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = client.AcquireTokenForClientAsync(scopes).Result
string token = result.AccessToken;
// ... use token
Run Code Online (Sandbox Code Playgroud)