1.Причина вызова 403 при вызове List VM Images API
Это потому, что ваше зарегистрированное приложение Azure AD не использует делегированные разрешения «API управления службами Windows Azure» правильно.Я говорю это потому, что вижу, что ваш код получает токен напрямую, используя идентификатор приложения (ClientCredential), а не как пользователь.
Пожалуйста, смотрите скриншоты ниже.Очевидно, что Window Azure Service Management API не предоставляет никаких разрешений для приложений, единственное, что можно использовать, - это делегированное разрешение.Если вы хотите больше узнать о разнице между двумя типами разрешений, прочитайте Разрешения в Azure AD .Короче говоря, при использовании делегированных разрешений приложению делегируются полномочия выступать в качестве зарегистрированного пользователя при совершении вызовов API.Поэтому должен быть зарегистрированный пользователь.
Я смог воспроизвести ошибку 403, используя ваш код, а затем заставить ее работать и вернуть список классических ВМ с некоторыми изменениями.Далее я объясню необходимые изменения.
Перейдите в Azure AD> Регистрация приложений> Ваше приложение> Настройки> Необходимые разрешения:


2.Изменения, необходимые для его работы
Изменение будет заключаться в том, чтобы получить токен как зарегистрированный пользователь, а не напрямую, используя clientId и секретный ключ приложения.Поскольку ваше приложение является консольным приложением, имеет смысл сделать что-то вроде этого, которое предложит пользователю ввести учетные данные:
var authenticationResult = await authenticationContext.AcquireTokenAsync(resourceUrl, clientId, new Uri(redirectUri), new PlatformParameters(PromptBehavior.Auto));
Кроме того, поскольку ваше приложение является консольным приложением, было бы лучшезарегистрировать его как «родное» приложение вместо веб-приложения, как у вас есть сейчас.Я говорю это потому, что консольные приложения или настольные клиентские приложения, которые могут работать в пользовательских системах, не защищены от обработки секретов приложений, поэтому вам не следует регистрировать их как «Веб-приложение / API» и не использовать в них никаких секретов, так как это представляет угрозу безопасности.
В общем, 2 изменения, и вам нужно идти.Как я уже говорил ранее, я попробовал это и вижу, что код работает нормально и получает список классических виртуальных машин.
a.Зарегистрируйте свое приложение в Azure AD как собственное приложение (т. Е. Тип приложения должен быть собственным, а не веб-приложением / API), затем в необходимых разрешениях добавьте «Window Azure Service Management API» и проверьте делегированные разрешения в соответствии с предыдущими снимками экрана в пункте 1.

b.Измените способ получения токена, чтобы делегированные разрешения могли использоваться в соответствии с зарегистрированным пользователем.Конечно, вошедший в систему пользователь должен иметь разрешения для виртуальной машины, которую вы пытаетесь перечислить, или, если у вас есть несколько пользователей, список будет отражать те виртуальные машины, к которым в данный момент вошел пользователь, имеющий доступ.
Вот всерабочий код после того, как я его изменил.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Net.Http;
using System.Net.Http.Headers;
namespace ListVMsConsoleApp
{
class Program
{
static void Main(string[] args)
{
string tenantId = "xxxxxx";
string clientId = "xxxxxx";
string redirectUri = "https://ListClassicVMsApp";
string apiNew = "https://management.azure.com/subscriptions/xxxxxxxx/providers/Microsoft.Compute/virtualMachines?api-version=2018-06-01";
string apiOld = "https://management.core.windows.net/xxxxxxxx/services/vmimages";
AzureRestClient client = new AzureRestClient(tenantId, clientId, redirectUri);
//OK - I can list the managed VMs.
//string resultNew = client.GetRequestAsync(apiNew).Result;
// 403 forbidden - should work now
string resultOld = client.GetRequestAsync(apiOld).Result;
}
}
public class AzureRestClient
{
private readonly HttpClient _client;
public AzureRestClient(string tenantName, string clientId, string redirectUri)
{
_client = CreateClient(tenantName, clientId, redirectUri).Result;
}
private async Task<string> GetAccessToken(string tenantName, string clientId, string redirectUri)
{
string authString = "https://login.microsoftonline.com/" + tenantName;
string resourceUrl = "https://management.core.windows.net/";
var authenticationContext = new AuthenticationContext(authString, false);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resourceUrl, clientId, new Uri(redirectUri), new PlatformParameters(PromptBehavior.Auto));
return authenticationResult.AccessToken;
}
async Task<HttpClient> CreateClient(string tenantName, string clientId, string redirectUri)
{
string token = await GetAccessToken(tenantName, clientId, redirectUri);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
client.DefaultRequestHeaders.Add("x-ms-version", "2014-02-01");
return client;
}
public async Task<string> GetRequestAsync(string url)
{
return await _client.GetStringAsync(url);
}
}
}