Аутентификация Dynamics 365 Web Api с вошедшим в систему пользователем приложения-функции Azure
У меня есть приложение-функция Azure (функция триггера HTTP), которое защищено проверкой подлинности Azure AD.
Это работает нормально - когда я захожу на URL-адрес функции в моем браузере. Сначала я перенаправлен на страницу входа, где я могу войти, используя свои учетные данные для входа в Azure Active Directory.
Однако я хочу, чтобы функция подключалась к веб-API Dynamics 365 и считывала некоторые данные, используя удостоверение вошедшего в систему пользователя. Я скопировал этот пример в отношении кода для подключения к веб-API и настройки разрешений приложения в Azure. Мой экземпляр Dynamics 365 находится в том же клиенте, что и мой Azure, и пользователь, в который я вошел, используя пользователя, который имеет доступ к Dynamics 365.
Часть, с которой я борюсь, - это получение токена доступа для вызова Dynamics Web API, который соответствует зарегистрированному пользователю.
Первая попытка
Затем я попытался использовать токен текущего зарегистрированного пользователя в соответствии с заголовком "X-MS-TOKEN-AAD-ID-TOKEN". Мой код выглядит следующим образом - он не подключается к веб-API Dynamics - я получаю 401 - Несанкционированный ответ:
[FunctionName("TestCrmFunction")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
var crmUrl = "https://myorganisation.crm11.dynamics.com";
// Get the token from the HTTP header of the request:
var token = req.Headers
.Where(x => x.Key == "X-MS-TOKEN-AAD-ID-TOKEN")
.SelectMany(x => x.Value)
.FirstOrDefault();
using (var httpClient = new HttpClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
httpClient.BaseAddress = new Uri(crmUrl);
// set the token here:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.GetAsync("api/data/v8.1/WhoAmI");
var content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
// I don't get here...
return req.CreateResponse(HttpStatusCode.OK, content);
}
else
{
// ... I get here
return req.CreateResponse(response.StatusCode, $"ERROR: {content}");
}
}
}
Похоже, что "X-MS-TOKEN-AAD-ID-TOKEN" не принимается.
Вторая попытка
Я пытаюсь получить новый токен для пользователя, создавая экземпляр "UserAssertion" вместе с ClientCredential. Бит UserAssertion, в котором я действительно не уверен и, вероятно, ошибочен:
var tenantId = "<my organisation tenantID>";
var authority = $"https://login.microsoftonline.com/{tenantId}";
var authenticationContext = new AuthenticationContext(authority, false);
// create the client credential using the clientID and clientSecret:
var clientId = "<my applicationId>";
var clientSecret = "<key for my application>";
var clientCredential = new ClientCredential(clientId, clientSecret);
// create the user assertion using the access token from the authenticated user:
var accessToken = req.Headers
.Where(x => x.Key == "X-MS-TOKEN-AAD-ACCESS-TOKEN")
.SelectMany(x => x.Value)
.FirstOrDefault();
var userAssertion = new UserAssertion(
accessToken,
"urn:ietf:params:oauth:grant-type:jwt-bearer",
ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn)?.Value);
// get a new token - this step is failing
var crmUrl = "https://myorganisation.crm11.dynamics.com";
AuthenticationResult authenticationResult =
await authenticationContext.AcquireTokenAsync(crmUrl, clientCredential, userAssertion);
string token = authenticationResult.AccessToken;
Я получаю ответ:
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS50027: Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid.
Обходной путь - не реальное решение
Единственное, что мне удалось получить - это жестко закодировать имя пользователя / пароль пользователя, с которым я вхожу в систему:
var credentials = new UserPasswordCredential("<my username>", "<my password>");
AuthenticationResult authenticationResult = await
authenticationContext.AcquireTokenAsync(crmUrl, clientId, credentials);
... но этот вид поражает цель - жестко закодировав имя пользователя / пароль, я, конечно, просто обхожу безопасность системы регистрации приложений Azure вообще?
2 ответа
Я буквально сделал то же самое, подключив приложение-функцию Azure и предоставив ему безопасные учетные данные для подключения к динамику 365, извлечения данных, выполнения некоторых манипуляций с данными и последующей записи данных обратно в Dynamics 365.
Пожалуйста, смотрите мой пост ниже, и если это поможет вашей ситуации, надеюсь, вы можете пометить это как ответ.
Аутентификация приложения-функции Azure для подключения к Dynamics 365 CRM онлайн
Это больше альтернатива, но, вероятно, легче достичь.
Если вы можете как-то идентифицировать текущего пользователя, например, читая подробности из токена. Затем вы можете подключиться к CRM, используя учетную запись службы, но настроить объект службы для олицетворения пользователя.
Выдавать себя за другого пользователя
Выдавать себя за пользователя
Чтобы выдать себя за пользователя, установите свойство CallerId в экземпляре OrganizationServiceProxy перед вызовом веб-методов службы.
// Retrieve the system user ID of the user to impersonate.
OrganizationServiceContext orgContext = new OrganizationServiceContext(_serviceProxy);
_userId = (from user in orgContext.CreateQuery<SystemUser>()
where user.FullName == "Something from your token" //perhaps domain name?
select user.SystemUserId.Value).FirstOrDefault();
// To impersonate another user, set the OrganizationServiceProxy.CallerId
// property to the ID of the other user.
_serviceProxy.CallerId = _userId;