我正在使用Microsoft Graph,并且已经创建了一个读取特定用户邮件的应用程序。
但是,在获得访问令牌并尝试读取邮件文件夹后,我收到401未经授权的答案。详细信息是:
令牌不包含任何权限,或者权限无法理解。
这似乎是一条非常清晰的信息,但是很遗憾,我无法找到解决方案。 这是我到目前为止所做的:
给予它 应用程序权限Mail.Read,Mail.ReadWrite (https://docs.microsoft.com/en-us/graph/api/user-list-mailfolders?view=graph-rest-1.0)
// 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());
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = client.AcquireTokenForClientAsync(scopes).Result;
string token = result.AccessToken;
到目前为止,一切都很好。我确实得到了令牌。
现在我想阅读邮件文件夹:
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(); }
这一次我收到一条401消息,其中包含详细信息:
令牌不包含任何权限,或者权限无法理解。
我已经搜索了互联网,但找不到答案来解释为什么我的令牌没有权限。
感谢您的时间!
更新1
如果我使用Graph Explorer来阅读邮件文件夹,则可以正常工作。此外:如果我从浏览器中获取令牌ID,并在第二段代码中使用它,那么我也将得到结果。因此,问题实际上是我从第一步收到的令牌。
答案 0 :(得分:3)
为确保此操作如您期望的那样,您应明确声明您希望为哪个租户获取访问令牌。 (在此租户中,该应用程序当然应该已经获得管理员的同意。)
使用特定于租户的端点代替“公共”令牌端点:
string url = "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token";
({tenant-id}
是租户(Guid)的租户ID或任何经过验证的域名。)
我也强烈建议反对自己构建令牌请求,如您在问题中所显示的。这对于教育目的可能是有用的,但从长远来看往往会变得不安全且容易出错。
您可以使用各种库来代替。下面是使用Microsoft Authentication Library (MSAL) for .NET的示例:
// 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