微軟動(dòng)態(tài)CRM專家羅勇 ,回復(fù)332或者20190505可方便獲取本文,同時(shí)可以在第一間得到我發(fā)布的最新博文信息,follow me!
本文很多內(nèi)容來(lái)自 John Towgood 撰寫的Dynamics 365 Online Authenticate with Client Credentials?,也著重參考了官方的?Use Single-Tenant server-to-server authentication?,我根據(jù)新的Azure Portal界面做了一些操作上的變化,并且改了一些代碼,還使用ADAL來(lái)簡(jiǎn)化代碼。
登錄?https://portal.azure.com?,點(diǎn)擊左邊的 【Azure Active Directory】 ,然后再點(diǎn)擊 【App registrations】 ,再點(diǎn)擊【New registration】
輸入一個(gè)合適的名稱,Supported account types保持默認(rèn)的?Accounts in this organizational directory only (Orgname) 不變,點(diǎn)擊【Register】按鈕。因?yàn)镽edirect URI用不上所以不輸入。
注冊(cè)成功后會(huì)產(chǎn)生 Application (client) ID,記錄下來(lái)備用,同時(shí)也記錄下 Directory (tenant) ID。
再點(diǎn)擊左邊的【API Permissions】,再點(diǎn)擊右邊的 【+ Add a permission】按鈕。
選擇 【Dynamics CRM】? (也可以選擇使用 PowerApps Runtime Serive 這個(gè)權(quán)限),
選擇 【Delegated permissions】 > 【user_impersonation】后點(diǎn)擊【Add permissions】按鈕。
?
?
?
然后點(diǎn)擊【Grant admin consent for Orgname】,
在彈出的提示中選擇【Yes】。
然后點(diǎn)擊【Certificates & secrets】 > 【+ New client secret】,輸入合適的Description,在點(diǎn)擊【Add】按鈕。
會(huì)自動(dòng)生成Client secrets,這里需要點(diǎn)擊生成的secret旁邊的【copy to clipboard】圖標(biāo)將其復(fù)制下來(lái),記得在這個(gè)步驟復(fù)制下來(lái),因?yàn)殡x開(kāi)這個(gè)頁(yè)面后就看不到這個(gè)secret了。
然后需要?jiǎng)?chuàng)建 一個(gè)Azure AD 用戶,點(diǎn)擊左側(cè)的【Azure Active Directory】> 【Users】。
然后點(diǎn)擊【New user】。
為用戶輸入Name,User Name,然后點(diǎn)擊【Create】按鈕。
最后還需要到Dynamics 365 Customer Engagement中創(chuàng)建一個(gè)Application User。導(dǎo)航到 Settings > Security > Users,切換到【Application Users】,點(diǎn)擊命令欄的【NEW】按鈕。
記得要切換到 APPLICATION USER這個(gè)窗體,輸入的內(nèi)容如下,Application ID就是前面步驟記錄的Application (client) ID,其余的就是前面步驟創(chuàng)建的Azure AD user信息。
保存后會(huì)自動(dòng)填充?Application ID URI 和 Azure AD Object ID 字段的值。
當(dāng)然還需要給這個(gè)用戶授予至少一個(gè)角色才行,官方建議不要授予系統(tǒng)標(biāo)準(zhǔn)角色,我這里復(fù)制了一個(gè)標(biāo)準(zhǔn)角色授予給他。
如果用Postman來(lái)獲取access token的話,如下圖:
下面就是用代碼如何做了,不多說(shuō),看代碼:
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; ? namespace UsingWebAPI { public class AuthenticationResponse { public string access_token { get; set; } public int expires_in { get; set; } public int expires_on { get; set; } public int ext_expires_in { get; set; } public int not_before { get; set; } public string resource { get; set; } public string token_type { get; set; } } class Program { ? static string resourceUrl = "https://crm219270.crm5.dynamics.com/"; static string clientId = "de8dd947-a3e3-48ec-8602-c3063f11dc29"; static string clientSecret = "5FsXh2*oNyLRm]Go1a9hD.[]=k54GNOZ"; static string tenantId = "3e28b187-1c5c-42f5-a1be-3f47570da35d"; static void Main(string[] args) { GetAuthenticationResponse(); Console.ReadKey(); } ? private static async void GetAuthenticationResponse() { List<KeyValuePair<string, string>> vals = new List<KeyValuePair<string, string>>(); ? vals.Add(new KeyValuePair<string, string>("client_id", clientId)); vals.Add(new KeyValuePair<string, string>("resource", resourceUrl)); vals.Add(new KeyValuePair<string, string>("grant_type", "client_credentials")); vals.Add(new KeyValuePair<string, string>("client_secret", clientSecret)); string tokenUrl = string.Format("https://login.windows.net/{0}/oauth2/token", tenantId); ? using (HttpClient httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache"); HttpContent content = new FormUrlEncodedContent(vals); HttpResponseMessage hrm = httpClient.PostAsync(tokenUrl, content).Result; AuthenticationResponse authenticationResponse = null; if (hrm.IsSuccessStatusCode) { string data = await hrm.Content.ReadAsStringAsync(); authenticationResponse = JsonConvert.DeserializeObject<AuthenticationResponse>(data); await DataOperations(authenticationResponse); } else { Console.WriteLine("Error." + hrm.ReasonPhrase); } } } ? private static async Task DataOperations(AuthenticationResponse authResult) { using (HttpClient httpClient = new HttpClient()) { httpClient.BaseAddress = new Uri(resourceUrl); httpClient.Timeout = new TimeSpan(, , ); //2 minutes httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0"); httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0"); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.access_token); string content = JsonConvert.SerializeObject(new { name = "A Account", telephone1 = ""}); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "api/data/v9.1/accounts"); request.Content = new StringContent(content); request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); HttpResponseMessage response = await httpClient.SendAsync(request); if (response.IsSuccessStatusCode) { Console.WriteLine("Account created."); } else { Console.WriteLine(String.Format("Failed to create account, reason is '{0}'.", response.ReasonPhrase)); } } } } }
當(dāng)然,如果使用ADAL的話,代碼會(huì)更加簡(jiǎn)單點(diǎn):
using Microsoft.IdentityModel.Clients.ActiveDirectory; using Newtonsoft.Json; using System; using System.Net.Http; using System.Net.Http.Headers; ? namespace UsingWebAPI { class Program { ? static string resourceUrl = "https://crm219270.crm5.dynamics.com/"; static string clientId = "de8dd947-a3e3-48ec-8602-c3063f11dc29"; static string clientSecret = "5FsXh2*oNyLRm]Go1a9hD.[]=k54GNOZ"; static string tenantId = "3e28b187-1c5c-42f5-a1be-3f47570da35d"; ? static void Main(string[] args) { AuthAndInvoke(); Console.ReadKey(); } ? private static async void AuthAndInvoke() { var credentials = new ClientCredential(clientId, clientSecret); var authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenantId); var result = await authContext.AcquireTokenAsync(resourceUrl, credentials); using (HttpClient httpClient = new HttpClient()) { httpClient.BaseAddress = new Uri(resourceUrl); httpClient.Timeout = new TimeSpan(, , ); //2 minutes httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0"); httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0"); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken); string content = JsonConvert.SerializeObject(new { name = "A Account", telephone1 = "" }); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "api/data/v9.1/accounts"); request.Content = new StringContent(content); request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); HttpResponseMessage response = await httpClient.SendAsync(request); if (response.IsSuccessStatusCode) { Console.WriteLine("Account created."); } else { Console.WriteLine(String.Format("Failed to create account, reason is '{0}'.", response.ReasonPhrase)); } } } } }
可以看到代碼創(chuàng)建的account的owner是我們前面步驟的Application User,是以該用戶身份在運(yùn)行的。
創(chuàng)作挑戰(zhàn)賽 新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔 為你收集整理的【转】!Dynamics 365 Online通过OAuth 2 Client Credential授权(Server-to-Server Authentication)后调用Web API 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。