【转】在无人值守程序(服务)中调用Microsoft Graph
什么是無人值守程序(服務(wù))
我在此前用了幾篇文章分別介紹了在桌面應(yīng)用程序(控制臺),Web應(yīng)用程序(ASP.NET MVC),以及PowerSehll腳本中如何訪問Microsoft Graph,今天這一篇要繼續(xù)講一個(gè)場景:在無人值守程序中訪問Microsoft Graph。那么什么是無人值守程序呢?通常我們將此類程序定義為不需要(不允許)用戶進(jìn)行干預(yù),一般用來在后臺自動(dòng)化運(yùn)行的程序。在英文文檔中,我們將其稱之為daemon application,廣義上說,也包括了服務(wù)這種特殊的應(yīng)用程序。
無人值守程序與Microsoft Graph的集成,要遵守一般的流程,但也有自己的一些特點(diǎn),總結(jié)起來有如下的步驟
關(guān)于這個(gè)話題,官方有一個(gè)英文的文檔,請參考?https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service
注冊應(yīng)用程序
針對Azure AD的不同版本,注冊應(yīng)用程序的過程我此前已經(jīng)有專門的文章介紹了,請參考
本文先演示注冊Azure AD 2.0應(yīng)用,具體的步驟就不做截圖了,唯一要提醒的是
配置應(yīng)用程序權(quán)限
這是無人值守應(yīng)用程序注冊的時(shí)候,要特別注意的。由于該程序是沒有用戶參與的,所以它無法使用某個(gè)特定用戶的身份做什么事情,而是使用一個(gè)統(tǒng)一的身份,該身份我們稱為Application Identity,而相應(yīng)的,我們要為程序申請的權(quán)限也是所謂的“Application Permissions”,而不是“Delegated Permissions”。
本例中,我想為應(yīng)用程序申請兩個(gè)權(quán)限:一個(gè)是用來獲取所有用戶信息的,另外一個(gè)是用來代替任何用戶發(fā)送郵件。
獲得管理員同意
由于無人值守的程序其實(shí)是自動(dòng)化運(yùn)行的,無需用戶進(jìn)行參與進(jìn)行授權(quán),而它進(jìn)行的操作,卻又有可能要代表用戶的行為。所以通常這些權(quán)限都需要得到真正的Office 365 Tenant管理員同意才能真正生效。
其實(shí)細(xì)心的朋友在上圖中也應(yīng)該可以看出來,幾乎所有Application Permission都是需要管理員同意的(Admin Consent)
要獲得管理員同意,你可以將下面的這個(gè)鏈接發(fā)送給用戶的Office 365 Tenant管理員
https://login.microsoftonline.com/common/adminconsent?client_id=dff48006-b010-4859-b5d5-68acdb821322&state=12345&redirect_uri=https://developer.microsoft.com/en-us/graph/
管理員需要在下面這樣的界面中對應(yīng)用程序所申請的權(quán)限進(jìn)行確認(rèn)
正常情況下,完成授權(quán)后頁面會(huì)被導(dǎo)航到下面的地址,請確認(rèn)admin_consent的值為true,并記錄下來tenant的值。這個(gè)表示用戶的Office 365 Tenant的編號,后面我們需要用到。
https://developer.microsoft.com/en-us/graph/?admin_consent=True&tenant=59723f6b-2d14-49fe-827a-8d04f9fe7a68&state=12345
獲取訪問令牌
無人值守應(yīng)用程序,不需要用戶參與進(jìn)行授權(quán),所以它獲取令牌的方式也略有不同。你可以在應(yīng)用程序里面使用下面的方式發(fā)起一個(gè)POST請求來獲得訪問令牌(Access Token)。
POST https://login.windows.net/59723f6b-2d14-49fe-827a-8d04f9fe7a68/oauth2/token Content-Type: application/x-www-form-urlencoded Host: login.windows.netclient_id=338c8e70-d0da-444e-b877-9f427a16eb17&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=8V59e4aBfNr6x4lN8EAMTisk3J7WRH+glZbvgMwdDQY=&grant_type=client_credentials正常情況下,這個(gè)請求將返回如下的結(jié)果
請復(fù)制得到的這個(gè)access_token的值。請注意,默認(rèn)情況下,這個(gè)access_token會(huì)在1個(gè)小時(shí)后過期。至于怎么刷新token,我會(huì)在后續(xù)文章中介紹。
使用令牌訪問資源
有了這個(gè)access_token,應(yīng)用程序就可以盡情地訪問Microsoft Graph的資源了。例如,通過下面的請求可以獲取到對應(yīng)的Office 365 Tenant中的所有用戶信息。
使用一個(gè)控制臺程序來實(shí)現(xiàn)代碼邏輯
上面演示的時(shí)候,我用了Fiddler這個(gè)小工具來模擬發(fā)起請求,并且快速地查看到結(jié)果。下面用一個(gè)簡單的應(yīng)用程序,來實(shí)現(xiàn)代碼邏輯,給大家參考。
這個(gè)程序使用了最簡單的代碼實(shí)現(xiàn),并添加了Newtonsoft.Json這個(gè)Package
using Newtonsoft.Json.Linq; using System; using System.Net.Http;namespace daemonapplication {class Program{static void Main(string[] args){//準(zhǔn)備環(huán)境var clientId = "dff48006-b010-4859-b5d5-68acdb821322";var client_secret = "uxO3frQOekCfdOfX2Oom4Vc";var tenantId = "59723f6b-2d14-49fe-827a-8d04f9fe7a68";var client = new HttpClient();//獲得令牌var request = new HttpRequestMessage(HttpMethod.Post, $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token");var body = new StringContent($"grant_type=client_credentials&client_id={clientId}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret={client_secret}");body.Headers.ContentType.MediaType = "application/x-www-form-urlencoded";request.Content = body;var access_token = JObject.Parse(client.SendAsync(request).Result.Content.ReadAsStringAsync().Result)["access_token"].ToString();//訪問資源request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/users");request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", access_token);var users = JObject.Parse(client.SendAsync(request).Result.Content.ReadAsStringAsync().Result)["value"];foreach (var item in users){Console.WriteLine($"displayName:{item["displayName"]},email:{item["email"]}");}Console.Read();}} }使用Azure AD 1.0
上面的例子很簡單易懂,但如果我們使用的是Azure AD 1.0(國際版同時(shí)支持1.0和2.0,中國版則只支持1.0),則注冊應(yīng)用程序和使用Microsoft Graph的方式會(huì)略有不同。
注冊Azure 1.0 應(yīng)用程序(中國版)
請參考之前的兩篇文章了解如何在Azure 1.0的環(huán)境中注冊應(yīng)用程序
和上面提到的一樣,有兩點(diǎn)需要注意
配置Azure 1.0 應(yīng)用程序權(quán)限(中國版)
和上面提到的一樣,這里需要申請Application permission,而不是delegation permission
這里需要注意修改Manifest文件(先下載,然后編輯,最后上傳),允許隱式授權(quán)?
獲得管理員同意 (中國版)
和Azure AD 2.0明顯不同的是,在1.0中,獲取管理員同意,需要使用如下的鏈接
https://login.chinacloudapi.cn/12c0cdab-3c40-4e86-80b9-3e6f98d2d344/oauth2/authorize?prompt=admin_consent&response_type=token&redirect_uri=https://developer.microsoft.com/en-us/graph/&resource=https://microsoftgraph.chinacloudapi.cn&client_id=3f56a5d5-7882-4290-9fd8-3908d734b3fe
此處的關(guān)鍵在于有一個(gè)prompt=admin_consent的參數(shù),正常情況下,管理員進(jìn)行授權(quán)確認(rèn)后會(huì)跳轉(zhuǎn)到下面這樣的地址,里面已經(jīng)包含了一個(gè)access_token
https://developer.microsoft.com/en-us/graph/#access_token=eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDckhLdnJ4N0cyU2FaYlpoLXREbnA3Z1BvSDFZc2w5MWlxU0x4Qmdqc1ZXODhmMDR5Vm11Tm1pZGlWZGFJclY5MEhLTl9aUXlXMENERlowcWdwRnBfOWw4Wkhpb21LdkNSM19LQURMdWZ3R1NBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIiwia2lkIjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIn0.eyJhdWQiOiJodHRwczovL21pY3Jvc29mdGdyYXBoLmNoaW5hY2xvdWRhcGkuY24iLCJpc3MiOiJodHRwczovL3N0cy5jaGluYWNsb3VkYXBpLmNuLzEyYzBjZGFiLTNjNDAtNGU4Ni04MGI5LTNlNmY5OGQyZDM0NC8iLCJpYXQiOjE0OTYyNDI0MjQsIm5iZiI6MTQ5NjI0MjQyNCwiZXhwIjoxNDk2MjQ2MzI0LCJhY3IiOiIxIiwiYWlvIjoiQVNRQTIvOEFBQUFBd2E2S3Y1YmVVRGtSVTliY2pBTzBKbFVJb0xaYzk3bEtkYW5hbzRzMFJTVT0iLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6ImRlYW1vbiIsImFwcGlkIjoiM2Y1NmE1ZDUtNzg4Mi00MjkwLTlmZDgtMzkwOGQ3MzRiM2ZlIiwiYXBwaWRhY3IiOiIwIiwiZmFtaWx5X25hbWUiOiLpmYgiLCJnaXZlbl9uYW1lIjoi5biM56ugIiwiaXBhZGRyIjoiMTgwLjE1Mi4yMi41MiIsIm5hbWUiOiLpmYgg5biM56ugIiwib2lkIjoiZjU1MjRmMTAtYTNlYy00Njg3LTllMzktNWFkNmU1ZTY3MDVhIiwicGxhdGYiOiIzIiwicHVpZCI6IjIwMDM3RkZFODExNjMyMDUiLCJzY3AiOiJNYWlsLlNlbmQgVXNlci5SZWFkLkFsbCIsInN1YiI6InhpckVWTFBtVG1BRFpJTW1sZTdBajZwS0NQU2JHMlNGU3EzN3JQaV9rWkUiLCJ0aWQiOiIxMmMwY2RhYi0zYzQwLTRlODYtODBiOS0zZTZmOThkMmQzNDQiLCJ1bmlxdWVfbmFtZSI6ImFyZXNAbW9kdHNwLnBhcnRuZXIub25tc2NoaW5hLmNuIiwidXBuIjoiYXJlc0Btb2R0c3AucGFydG5lci5vbm1zY2hpbmEuY24iLCJ1dGkiOiJRSEswVy0xdXcwbTlxWW9TekNvRUFBIiwidmVyIjoiMS4wIn0.EZhZhKFXzS1hVkz5HNEFSG9lcL6CSRyjqRNEMTYpM0Q4wp7UICf1_61PQFCe_5opnZlEMl-e7sHJ2W4Ni1hqjASUxOamFoQ5pBVNQ-WgEfhX_QPJXLBbyMdFguRPdrXy1AqzYGqFQ_mtmjqFa0w7nXf4LI7vgx7MRPMm5YDljnK4vk4oXC9M7fb4EcU7g26XrBUnTz6Es_IGT9SUqAXYLDjfI3dC06GqtjRrTwtd0AYwbbUPZ288j4XZ_fb8x1lj97ZpIFZh-STnIZUatIij0dFphMrFhUig0YbMtCxlfsrpZgPyuwlrrXbnj5fgWw1ABj3xKrEaWbVt5XCT4T9-aA&token_type=Bearer&expires_in=3599&session_state=022f05fb-4b3f-4f86-b593-cbda90232a7a&admin_consent=True
獲取訪問令牌(中國版)
這一步可以跳過,因?yàn)樯厦孢@一步已經(jīng)獲得了access_token
使用令牌訪問資源(中國版)
using System; using System.Net.Http; using System.Threading.Tasks;namespace ConsoleApp6 {class Program{static void Main(string[] args){var result = GetUsers().Result;Console.WriteLine(result);Console.Read();}static async Task<string> GetUsers(){var token = "eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDckhLdnJ4N0cyU2FaYlpoLXREbnA3Z1BvSDFZc2w5MWlxU0x4Qmdqc1ZXODhmMDR5Vm11Tm1pZGlWZGFJclY5MEhLTl9aUXlXMENERlowcWdwRnBfOWw4Wkhpb21LdkNSM19LQURMdWZ3R1NBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIiwia2lkIjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIn0.eyJhdWQiOiJodHRwczovL21pY3Jvc29mdGdyYXBoLmNoaW5hY2xvdWRhcGkuY24iLCJpc3MiOiJodHRwczovL3N0cy5jaGluYWNsb3VkYXBpLmNuLzEyYzBjZGFiLTNjNDAtNGU4Ni04MGI5LTNlNmY5OGQyZDM0NC8iLCJpYXQiOjE0OTYyNDI0MjQsIm5iZiI6MTQ5NjI0MjQyNCwiZXhwIjoxNDk2MjQ2MzI0LCJhY3IiOiIxIiwiYWlvIjoiQVNRQTIvOEFBQUFBd2E2S3Y1YmVVRGtSVTliY2pBTzBKbFVJb0xaYzk3bEtkYW5hbzRzMFJTVT0iLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6ImRlYW1vbiIsImFwcGlkIjoiM2Y1NmE1ZDUtNzg4Mi00MjkwLTlmZDgtMzkwOGQ3MzRiM2ZlIiwiYXBwaWRhY3IiOiIwIiwiZmFtaWx5X25hbWUiOiLpmYgiLCJnaXZlbl9uYW1lIjoi5biM56ugIiwiaXBhZGRyIjoiMTgwLjE1Mi4yMi41MiIsIm5hbWUiOiLpmYgg5biM56ugIiwib2lkIjoiZjU1MjRmMTAtYTNlYy00Njg3LTllMzktNWFkNmU1ZTY3MDVhIiwicGxhdGYiOiIzIiwicHVpZCI6IjIwMDM3RkZFODExNjMyMDUiLCJzY3AiOiJNYWlsLlNlbmQgVXNlci5SZWFkLkFsbCIsInN1YiI6InhpckVWTFBtVG1BRFpJTW1sZTdBajZwS0NQU2JHMlNGU3EzN3JQaV9rWkUiLCJ0aWQiOiIxMmMwY2RhYi0zYzQwLTRlODYtODBiOS0zZTZmOThkMmQzNDQiLCJ1bmlxdWVfbmFtZSI6ImFyZXNAbW9kdHNwLnBhcnRuZXIub25tc2NoaW5hLmNuIiwidXBuIjoiYXJlc0Btb2R0c3AucGFydG5lci5vbm1zY2hpbmEuY24iLCJ1dGkiOiJRSEswVy0xdXcwbTlxWW9TekNvRUFBIiwidmVyIjoiMS4wIn0.EZhZhKFXzS1hVkz5HNEFSG9lcL6CSRyjqRNEMTYpM0Q4wp7UICf1_61PQFCe_5opnZlEMl-e7sHJ2W4Ni1hqjASUxOamFoQ5pBVNQ-WgEfhX_QPJXLBbyMdFguRPdrXy1AqzYGqFQ_mtmjqFa0w7nXf4LI7vgx7MRPMm5YDljnK4vk4oXC9M7fb4EcU7g26XrBUnTz6Es_IGT9SUqAXYLDjfI3dC06GqtjRrTwtd0AYwbbUPZ288j4XZ_fb8x1lj97ZpIFZh-STnIZUatIij0dFphMrFhUig0YbMtCxlfsrpZgPyuwlrrXbnj5fgWw1ABj3xKrEaWbVt5XCT4T9-aA";HttpClient client = new HttpClient();client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);HttpResponseMessage response = await client.GetAsync("https://microsoftgraph.chinacloudapi.cn/v1.0/users/");string retResp = await response.Content.ReadAsStringAsync();return retResp;}} }如果我們將代碼再演化一下,使用Microsoft.Graph進(jìn)行訪問的話,會(huì)更加輕松愜意,因?yàn)榭梢酝耆趶?qiáng)類型的方式進(jìn)行操作
using Microsoft.Graph; using System; using System.Threading.Tasks; using System.Linq;namespace ConsoleApp6 {class Program{static void Main(string[] args){var result = GetUsers().Result;foreach (var item in result){Console.WriteLine(item.DisplayName);}Console.Read();}static async Task<IGraphServiceUsersCollectionPage> GetUsers(){var token = "eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDckhLdnJ4N0cyU2FaYlpoLXREbnA3Z1BvSDFZc2w5MWlxU0x4Qmdqc1ZXODhmMDR5Vm11Tm1pZGlWZGFJclY5MEhLTl9aUXlXMENERlowcWdwRnBfOWw4Wkhpb21LdkNSM19LQURMdWZ3R1NBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIiwia2lkIjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIn0.eyJhdWQiOiJodHRwczovL21pY3Jvc29mdGdyYXBoLmNoaW5hY2xvdWRhcGkuY24iLCJpc3MiOiJodHRwczovL3N0cy5jaGluYWNsb3VkYXBpLmNuLzEyYzBjZGFiLTNjNDAtNGU4Ni04MGI5LTNlNmY5OGQyZDM0NC8iLCJpYXQiOjE0OTYyNDI0MjQsIm5iZiI6MTQ5NjI0MjQyNCwiZXhwIjoxNDk2MjQ2MzI0LCJhY3IiOiIxIiwiYWlvIjoiQVNRQTIvOEFBQUFBd2E2S3Y1YmVVRGtSVTliY2pBTzBKbFVJb0xaYzk3bEtkYW5hbzRzMFJTVT0iLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6ImRlYW1vbiIsImFwcGlkIjoiM2Y1NmE1ZDUtNzg4Mi00MjkwLTlmZDgtMzkwOGQ3MzRiM2ZlIiwiYXBwaWRhY3IiOiIwIiwiZmFtaWx5X25hbWUiOiLpmYgiLCJnaXZlbl9uYW1lIjoi5biM56ugIiwiaXBhZGRyIjoiMTgwLjE1Mi4yMi41MiIsIm5hbWUiOiLpmYgg5biM56ugIiwib2lkIjoiZjU1MjRmMTAtYTNlYy00Njg3LTllMzktNWFkNmU1ZTY3MDVhIiwicGxhdGYiOiIzIiwicHVpZCI6IjIwMDM3RkZFODExNjMyMDUiLCJzY3AiOiJNYWlsLlNlbmQgVXNlci5SZWFkLkFsbCIsInN1YiI6InhpckVWTFBtVG1BRFpJTW1sZTdBajZwS0NQU2JHMlNGU3EzN3JQaV9rWkUiLCJ0aWQiOiIxMmMwY2RhYi0zYzQwLTRlODYtODBiOS0zZTZmOThkMmQzNDQiLCJ1bmlxdWVfbmFtZSI6ImFyZXNAbW9kdHNwLnBhcnRuZXIub25tc2NoaW5hLmNuIiwidXBuIjoiYXJlc0Btb2R0c3AucGFydG5lci5vbm1zY2hpbmEuY24iLCJ1dGkiOiJRSEswVy0xdXcwbTlxWW9TekNvRUFBIiwidmVyIjoiMS4wIn0.EZhZhKFXzS1hVkz5HNEFSG9lcL6CSRyjqRNEMTYpM0Q4wp7UICf1_61PQFCe_5opnZlEMl-e7sHJ2W4Ni1hqjASUxOamFoQ5pBVNQ-WgEfhX_QPJXLBbyMdFguRPdrXy1AqzYGqFQ_mtmjqFa0w7nXf4LI7vgx7MRPMm5YDljnK4vk4oXC9M7fb4EcU7g26XrBUnTz6Es_IGT9SUqAXYLDjfI3dC06GqtjRrTwtd0AYwbbUPZ288j4XZ_fb8x1lj97ZpIFZh-STnIZUatIij0dFphMrFhUig0YbMtCxlfsrpZgPyuwlrrXbnj5fgWw1ABj3xKrEaWbVt5XCT4T9-aA";GraphServiceClient client = new GraphServiceClient(new DelegateAuthenticationProvider(async (request) =>{await Task.Run(() => { request.Headers.Add("Authorization", $"Bearer {token}"); });}));client.BaseUrl = "https://microsoftgraph.chinacloudapi.cn/v1.0";var result = client.Users.Request().GetAsync().Result;return result;}} }總結(jié)
以上是生活随笔為你收集整理的【转】在无人值守程序(服务)中调用Microsoft Graph的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 比AirPods还轻 世界最轻鼠标亮相:
- 下一篇: 【转】Microsoft Teams快速