从 C# 控制台应用程序使用图形 API 时出现 404 错误
404 error on using graph API from c# console app
我目前正在尝试使用我的 C# 对 Graph API 进行身份验证。当我调用相同的 API 时,我能够查询此 API 并从 Postman.But 成功接收令牌,我收到 404 错误。
我的代码如下:
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace GraphTest
{
public class AuthenticationModel
{
public string grantType { get; set; } = "client_credentials";
public string clientId { get; set; } = "my_ad_app_id";
public string clientSecret { get; set; } = "client_secret";
public string scope { get; set; } = "https://graph.microsoft.com/.default";
}
public class Authentication
{
private static string tenantId = "tenant_id";
private static readonly HttpClient Client = new HttpClient();
public Authentication()
{
var authenticationModel = new AuthenticationModel();
RunAsync().GetAwaiter().GetResult();
}
private static async Task RunAsync()
{
Client.BaseAddress = new Uri("https://login.microsoftonline.com/");
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("*/*"));
Client.DefaultRequestHeaders.Add("Host", "login.microsoftonline.com");
Client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
try
{
var authenticationModel = new AuthenticationModel();
var url = await GetTokenAsync(authenticationModel);
Console.WriteLine($"Created at {url}");
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
}
private static async Task<Uri> GetTokenAsync(AuthenticationModel authenticationModel)
{
var keyValues = authenticationModel.GetType().GetProperties()
.ToList()
.Select(p => $"{p.Name} = {p.GetValue(authenticationModel)}")
.ToArray();
var xUrlEncodedBody = string.Join('&', keyValues);
var response = await Client.PostAsJsonAsync(
$"{tenantId}/oauth2/v2.0/token", xUrlEncodedBody);
response.EnsureSuccessStatusCode();
return response;
}
}
}
所以,我收到了这样的回复:StatusCode:404, ReasonPhrase:Not Found
请帮助我知道我哪里做错了。
注意:API 具有相同数据的 Postman 工作正常。不过,出于安全原因,我在这里替换了一些值。
我 运行 你的代码,它错误地生成了如下 spaces 的查询字符串。
xUrlEncodedBody => grantType = client_credentials&clientId = my_ad_app_id&clientSecret = client_secret&scope = https://graph.microsoft.com/.default
查询参数名称和值之间有 space,见下行。
.Select(p => $"{p.Name} = {p.GetValue(authenticationModel)}")
删除 space 并重试
.Select(p => $"{p.Name}={p.GetValue(authenticationModel)}")
您不应 post 将 URL 编码内容形成为 JSON (PostAsJsonAsync
)。正文需要具有 application/x-www-form-urlencoded
.
的内容类型
但退一步说,当有库可以为您完成协议时,您不需要自己实现协议 :)。我们提供并支持 Microsoft Authentication Library (MSAL) 让这一切变得简单。
var app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithTenantId("{tenantID}")
.WithClientSecret(config.ClientSecret)
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
catch (MsalServiceException ex)
{
Console.WriteLine($"Error getting token: {ex.Message}");
}
Console.WriteLine($"Token: {result.AccessToken}");
我目前正在尝试使用我的 C# 对 Graph API 进行身份验证。当我调用相同的 API 时,我能够查询此 API 并从 Postman.But 成功接收令牌,我收到 404 错误。
我的代码如下:
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace GraphTest
{
public class AuthenticationModel
{
public string grantType { get; set; } = "client_credentials";
public string clientId { get; set; } = "my_ad_app_id";
public string clientSecret { get; set; } = "client_secret";
public string scope { get; set; } = "https://graph.microsoft.com/.default";
}
public class Authentication
{
private static string tenantId = "tenant_id";
private static readonly HttpClient Client = new HttpClient();
public Authentication()
{
var authenticationModel = new AuthenticationModel();
RunAsync().GetAwaiter().GetResult();
}
private static async Task RunAsync()
{
Client.BaseAddress = new Uri("https://login.microsoftonline.com/");
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("*/*"));
Client.DefaultRequestHeaders.Add("Host", "login.microsoftonline.com");
Client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
try
{
var authenticationModel = new AuthenticationModel();
var url = await GetTokenAsync(authenticationModel);
Console.WriteLine($"Created at {url}");
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
}
private static async Task<Uri> GetTokenAsync(AuthenticationModel authenticationModel)
{
var keyValues = authenticationModel.GetType().GetProperties()
.ToList()
.Select(p => $"{p.Name} = {p.GetValue(authenticationModel)}")
.ToArray();
var xUrlEncodedBody = string.Join('&', keyValues);
var response = await Client.PostAsJsonAsync(
$"{tenantId}/oauth2/v2.0/token", xUrlEncodedBody);
response.EnsureSuccessStatusCode();
return response;
}
}
}
所以,我收到了这样的回复:StatusCode:404, ReasonPhrase:Not Found
请帮助我知道我哪里做错了。
注意:API 具有相同数据的 Postman 工作正常。不过,出于安全原因,我在这里替换了一些值。
我 运行 你的代码,它错误地生成了如下 spaces 的查询字符串。
xUrlEncodedBody => grantType = client_credentials&clientId = my_ad_app_id&clientSecret = client_secret&scope = https://graph.microsoft.com/.default
查询参数名称和值之间有 space,见下行。
.Select(p => $"{p.Name} = {p.GetValue(authenticationModel)}")
删除 space 并重试
.Select(p => $"{p.Name}={p.GetValue(authenticationModel)}")
您不应 post 将 URL 编码内容形成为 JSON (PostAsJsonAsync
)。正文需要具有 application/x-www-form-urlencoded
.
但退一步说,当有库可以为您完成协议时,您不需要自己实现协议 :)。我们提供并支持 Microsoft Authentication Library (MSAL) 让这一切变得简单。
var app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithTenantId("{tenantID}")
.WithClientSecret(config.ClientSecret)
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
catch (MsalServiceException ex)
{
Console.WriteLine($"Error getting token: {ex.Message}");
}
Console.WriteLine($"Token: {result.AccessToken}");