Получение токена доступа OpenID Connect/OAuth для вызова MS Dynamics

avatar
marc_s
8 августа 2021 в 20:01
354
1
3

Я пытаюсь разобраться в "современных" методах аутентификации и иметь дело с OAuth и токеном доступа для вызова внешних служб в ASP.NET Core 5 MVC.

У меня есть регистрация приложения в Azure, которая настроена нормально — это разрешения API для этого приложения:

enter image description here

Моей целью является вызов MS Graph (несколько вызовов), а также MS Dynamics365 для сбора некоторой информации. Мне удалось настроить аутентификацию с помощью OAuth (или это OpenID Connect? Я никогда не уверен, как отличить эти два друг от друга) в моем приложении MVC, например (в Startup.cs):

/* in appsettings.json:
"MicrosoftGraph": {
    "Scopes": "user.read organization.read.all servicehealth.read.all servicemessage.read.all",
    "BaseUrl": "https://graph.microsoft.com/v1.0"
},
*/

public void ConfigureServices(IServiceCollection services)
{
    List<string> initialScopes = Configuration.GetValue<string>("MicrosoftGraph:Scopes")?.Split(' ').ToList();

    services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
        .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
        .AddInMemoryTokenCaches();
    
    // further service setups
}

Все работает нормально — мне предлагается войти в систему, предоставить свои учетные данные, и в моем приложении MVC я могу проверить участников утверждений с их утверждениями после входа в систему — пока все выглядит нормально.

Следующий шаг — вызов нижестоящих API. Я изучил некоторые сообщения в блогах и учебные пособия и придумал это решение для получения токена доступа на основе имени scope, которое мне нужно для данного вызова. Это мой код здесь (на странице Razor, используемой для отображения данных, полученных из MS Graph):

public async Task OnGetAsync()
{
    List<string> scopes = new List<string>();
    scopes.Add("Organization.Read.All");

    // fetch the OAuth access token for calling the MS Graph API
    var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);

    HttpClient client = _factory.CreateClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    client.DefaultRequestHeaders.Add("Accept", "application/json");

    string graphUrl = "https://graph.microsoft.com/v1.0/subscribedSkus";
                       
    string responseJson = await client.GetStringAsync(graphUrl);
    
    // further processing and display of data fetched from MS Graph
}

Для областей MS Graph это работает просто отлично — я получаю свой токен доступа, я могу передать его моему HttpClient, и вызов MS Graph завершается успешно, и я получаю нужную информацию.

Проблема начинается при попытке использовать тот же метод для получения маркера доступа для вызова MS Dynamics. Я предполагал, что просто указываю имя разрешения API, которое определено в регистрации Azure AD — user_impersonation — вот так:

public async Task OnGetAsync()
{
    List<string> scopes = new List<string>();
    scopes.Add("user_impersonation");

    var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
    // further code
}

Но теперь я не получаю ничего, кроме ошибок, таких как эта:

При обработке запроса произошло необработанное исключение.
MsalUiRequiredException: AADSTS65001: пользователь или администратор не дал согласия на использование приложения с идентификатором «257a582c-4461-40a4-95c3-2f257d2f8693» с именем «BFH_Dyn365_Monitoring». Отправьте интерактивный запрос авторизации для этого пользователя и ресурса.

что забавно, потому что согласие администратора было предоставлено - поэтому я не совсем уверен, в чем проблема.....

enter image description here

Затем я подумал, что, возможно, мне нужно добавить user_impersonation в список начальных областей видимости (как определено в appsettings.json и используется в методе Startup.ConfigureServices), но добавление этого приводит к другой забавной ошибке:

При обработке запроса произошло необработанное исключение.
OpenIdConnectProtocolException: сообщение содержит ошибку: «invalid_client», error_description: «AADSTS650053: приложение «BFH_Dyn365_Monitoring» запросило область «user_impersonation», которая не существует в ресурсе «00000003-0000-0000-c000-000000000000». Свяжитесь с поставщиком приложения.

Странная вещь - как вы видели на самом первом снимке экрана - область ЕСТЬ присутствует при регистрации приложения - поэтому я не совсем уверен, почему это исключение выдается....

Может ли кто-нибудь пролить свет, возможно, из опыта вызова MS Dynamics с использованием токена OAuth? Это принципиально невозможно, или я где-то пропустил шаг или два?

Спасибо! Марк

Источник

Ответы (1)

avatar
Philippe Signoret
11 августа 2021 в 11:08
4

Чтобы получить токен для user_impersonation для Dynamics (вместо Microsoft Graph), необходимо использовать значение полной области: "{your CRM URL}/user_impersonation".

Полный формат значений параметра scopes в GetAccessTokenForUserAsync: {resource}/{scope}, где {resource} – идентификатор или URI API, к которому вы пытаетесь получить доступ, а {scope} – делегированный разрешение на этом ресурсе.

Если вы опускаете часть {resource}, платформа Microsoft Identity предполагает, что вы имеете в виду Microsoft Graph. Таким образом, "Organization.Read.All" интерпретируется как "https://graph.microsoft.com/Organization.Read.All".

При попытке запросить токен для "user_impersonation" запрос завершается ошибкой, поскольку такое разрешение не было предоставлено для Microsoft Graph. На самом деле таких разрешений даже не существует (для Microsoft Graph), что объясняет другую ошибку, которую вы видите.

marc_s
11 августа 2021 в 14:40
0

И вуаля ! Вот и все ! При таком подходе я получаю действительный токен доступа для Dynamics при регистрации приложения Azure AD — большое спасибо! Хотел бы я проголосовать за это в 100 раз! :-)