Недавно я проделал нечто подобное, но не использовал функцию аутентификации подписки Azure для подключения к D365. В моем случае поступали вызовы к функциям Azure из других мест, но обратное соединение ничем не отличается. Аутентификация не проходит ни в одном из этих случаев. Если пользователь AAD проходит аутентификацию в вашем приложении Function, вам все равно необходимо подключиться к D365 с помощью пользователя приложения, а затем выдать себя за пользователя, который вас вызвал.
Сначала убедитесь, что приложение, зарегистрированное в Azure AD в разделе «Регистрация приложений», имеет тип «Веб-приложение / API», а не «Собственное». Отредактируйте настройки зарегистрированного приложения и убедитесь, что:
- Не берите идентификатор приложения, который я буду называть позже appId.
- В разделе «Доступ к API - необходимые разрешения» добавьте Dynamics CRM Online (Microsoft.CRM) и NOT Dynamics 365.
- В разделе «Доступ к API - ключи» создайте ключ с соответствующим сроком действия. Вы можете создать несколько ключей, если у вас есть несколько функций / приложений, подключающихся обратно, как это «приложение». Я буду называть этот ключ "clientSecret" позже.
Если опция «Ключи» недоступна, вы зарегистрировали собственное приложение.
Я сохранил appId и clientSecret в разделе конфигурации приложения в приложении Function и получил к ним доступ, используя обычную коллекцию System.Configuration.ConfigurationManager.AppSettings.
В приведенных ниже примерах используется вызов AuthenticationParameters для поиска URL-адресов полномочий и ресурсов, но вы также можете легко создать эти URL-адреса вручную, используя бесчисленное множество примеров в Интернете. Я считаю, что это просто обновится само, если они когда-либо изменятся, так что меньше работать позже.
Это простые примеры, и я преуменьшаю необходимость обновить токены и все такое.
Затем для доступа к D365 с использованием OData:
string odataUrl = "https://org.crm6.dynamics.com/api/data/v8.2/"; // trailing slash actually matters
string appId = "some-guid";
string clientSecret = "some key";
AuthenticationParameters authArg = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(odataUrl)).Result;
AuthenticationContext authCtx = new AuthenticationContext(authArg.Authority);
AuthenticationResult authRes = authCtx.AcquireTokenAsync(authArg.Resource, new ClientCredential(appId, clientSecret)).Result;
using (HttpClient client = new HttpClient()) {
client.TimeOut = TimeSpan.FromMinutes (2);
client.DefaultRequestHeaders.Add("Authorization", authRes.CreateAuthorizationHeader ());
using (HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, $"{odataUrl}accounts?$select=name&$top=10")) {
using (HttpResponseMessage res = client.SendAsync(req).Result) {
if (res.IsSuccessStatusCode) {
Console.WriteLine(res.Content.ReadAsStringAsync().Result);
}
else {
// cry
}
}
}
}
Если вы хотите получить доступ к D365 с помощью службы организации и LINQ, используйте следующее. Две основные части, которые мне потребовалось некоторое время, чтобы выяснить, это формат этого странно выглядящего URL organization.svc и использование Microsoft.Xrm.Sdk.WebServiceClient.OrganizationWebProxyClient вместо Tooling:
string odataUrl = "https://org.crm6.dynamics.com/xrmservices/2011/organization.svc/web?SdkClientVersion=8.2"; // don't question the url, just accept it.
string appId = "some-guid";
string clientSecret = "some key";
AuthenticationParameters authArg = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(odataUrl)).Result;
AuthenticationContext authCtx = new AuthenticationContext(authArg.Authority);
AuthenticationResult authRes = authCtx.AcquireTokenAsync(authArg.Resource, new ClientCredential(appId, clientSecret)).Result;
using (OrganizationWebProxyClient webProxyClient = new OrganizationWebProxyClient(new Uri(orgSvcUrl), false)) {
webProxyClient.HeaderToken = authRes.AccessToken;
using (OrganizationServiceContext ctx = new OrganizationServiceContext((IOrganizationService)webProxyClient)) {
var accounts = (from i in ctx.CreateQuery("account") orderby i["name"] select i).Take(10);
foreach (var account in accounts)
Console.WriteLine(account["name"]);
}
}
Не уверен, в каком контексте вы вернетесь при регистрации в Webhook, еще не пробовал, но просто удостоверьтесь, что в заголовке авторизации обычно есть токен-носитель, и два приведенных выше примера вводят его по-разному, поэтому вам следует быть в состоянии соединить то, что нужно отсюда.