2019年10月30日 星期三

Github 快速上手 1 : 環境的安裝與設定

Github 快速上手 1 : 環境的安裝與設定

當我在進行 Xamarin.Forms 課程教學的時候,當學員所練習的專案有問題時候,我都會建議學員把專案原始碼提供給我,好方便進行除錯,可是,通常學員給我的該練習專案的壓縮檔案都非常大,幾乎超過 80MB 以上、甚至更大,而,就算請學員把專案原始碼推入到 Github Repository 上,該 Repository 的檔案體積也是十分的大;這是因為在進行 git commit 簽入時候,把許多二進位元檔案也簽入進去了,而這些二進位元檔案是 Visual Studio 在建置時期產生的,其實不需要簽入或者儲存起來,因為,下次建置的時候,就會重新產生出來了。
因此,在這裡撰寫了兩篇系列文章,方便學員參考了解 Github 這個工具的使用過程
這裡將會說明如何在第一次使用 Github 功能的時候,如何申請帳號、安裝相關軟體、進行設定
這裡將會說明如何建立 Github Repository、複製該 Repository 到本機電腦內、簽入忽略二進位元的設定到 Github Repository 內、簽入 Xamarin.Forms 的專案、使用 TortoiseGit 工具清除本機 Repository 內的二進位元檔案。
在這系列文章中,假設開發者已經有安裝了 Visual Studio 2017 或者 Visual Studio 2019 開發工具。

申請 Github 帳號

若還沒有 Github 帳號,可以參考底下的步驟來進行申請,若已經有 Github 帳號,則可以跳過有關 Github 帳號申請說明的內容,直接進入到下一段內容。
在打開 Github 網站之後,將會看到該網頁的左方有 [Username] 、 [Email] 、 [Passowrd] 三個文字輸入盒,請在這裡輸入你自己的相關資訊,完成後,請點選 [Sing Up for Github] 這個按鈕,申請一個免費的 Github 帳號。
此時,Github 網站需要進行驗證,請點選中間的 [驗證] 按鈕
請依照網頁文字說明指示內容進行操作,完成後,將會看到如上圖的文字,表示驗證完成,此時,可以點選螢幕上的 [完成] 按鈕。
現在,可以點選下方的 [Next: Select a plan] 按鈕,不過,在這裡有勾選 Email preferences 的選項 [Send me occasional product updates, announcements, and offers.]
在此,可以選擇免費 [Free] 的方案即可,請點選 [Choose Free] 這個按鈕
當看到歡迎來到 Github 網站的訊息,請使用滑鼠轉動到最下方。
在這裡將可以點選 [Complete setup] 按鈕,不過,將會使用直接點選 [Skit this setp]
好的,請檢查剛剛申請帳號使用的 Email 信箱,打開 Github 寄送來的驗證郵件
請點選郵件上的 [Verify email address] 藍色按鈕,或者底下的 URL 連結
現在已經完成了 Github 帳號的申請作業了

確認與 Git for Windows 有安裝

請先確認電腦中是否已經有安裝 Git for Windows
在桌面左下角,點選放大鏡或者在 [搜尋方塊] 中輸入 git 文字,若這個時候沒有找到任何應用程式,那就表示這台電腦上還沒有安裝 [Git for Windows] 這個應用程式。
若沒有的話,可以透過 Visual Studio Installer 工具來協助安裝。
Visual Studio Installer
在電腦中找到 [Visual Studio Installer] 這個應用程式
當 Visual Studio Installer 安裝程式啟動起來之後,請點選 [個別元件] 標籤頁次,可以在 [程式碼工具] 區段中,找到 [Git for Windows] 這個選項,若該選項尚未勾選,請勾選這個選項,把它安裝起來。
現在再度在桌面左下角,點選放大鏡或者在 [搜尋方塊] 中輸入 git 文字,此時將會看到上面的螢幕截圖,表示這電腦上已經有安裝 [Git for Windows] 這個應用程式。

安裝 TortoiseGit

為了要能夠透過 [檔案總管] 來進行 [Github] 的同步與操作更多功能,在這裡可以先安裝 [TortoiseGit] 這個工具;請先使用瀏覽器打開這個網址 https://tortoisegit.org/
在 [TortoiseGit] 網頁上,將會看到 [Download] 按鈕,請點選這個按鈕
當 [Download] 網頁出現之後,可以選擇 [for 64-bit Windows] 文字下方的檔案下載連結,這裡看到的是 Download TortoiseGit 2.8.0 - 64-bit 準備下載與進行安裝這個工具。
[TortoiseGit] 安裝程式啟動之後,請點選 [Next] 按鈕
在 [Information] 對話窗中,點選 [Next] 這個按鈕
在 [Choose SSH Client] 對話窗中,使用預設值,點選 [Next] 這個按鈕
在 [Custom Setup] 對話窗中,使用預設值,點選 [Next] 這個按鈕
在 [Ready to Install] 對話窗中,點選 [Install] 這個按鈕,準備開始進行安裝作業。
現在已經安裝完成了,請點選 [Finish] 按鈕,準備進行第一次精靈的設定
在 [Welcome to TortoiseGit] 對話窗中,使用預設值,點選 [下一步] 這個按鈕
在 [Welcome to TortoiseGit] 對話窗中,使用預設值,點選 [下一步] 這個按鈕
在 [Configure git.exe] 對話窗中,點選中間右方的 [Check now] 按鈕,此時,在該按鈕的左方會出現這台電腦已經安裝 Git 工具版本,這裡顯示的是 [git version 2.17.1.windows.2] ,最後請點選 [下一步] 這個按鈕
在 [Configure user information] 對話窗中,請在 [Name] 與 [Email] 欄位中,輸入你的相關資訊,點選 [Next] 這個按鈕
在 [Authentication and credential store] 對話窗中,使用預設值,點選 [完成] 這個按鈕
在 [Information] 對話窗中,使用預設值,點選 [Next] 這個按鈕



2019年9月25日 星期三

使用 Microsoft.Graph NuGet 套件 來存取 Office 365 行事曆的功能

使用 Microsoft.Graph NuGet 套件 來存取 Office 365 行事曆的功能

現在要來使用 Microsoft.Graph 套件所提供的 API,進行新增一筆行事曆事件,想要使用這個功能,那就需要先完成前一篇的文章 使用 MSAL.NET 的 Resource Owner Password Credential ROPC 架構來取得存取權杖但是無須透過瀏覽器來進行身分驗證 的程式碼練習,透過該文章中的說明方法,就可以取得要存取 Microsoft Graph API 所需要用到的 Access Token。
在這篇文章所提到的專案原始碼,可以從 GitHub 下載

建立測試專案

在這篇文章中,將會使用一個 Console 主控台應用程式類型的專案,來進行設計這樣的需求,也就是說,在無需與使用者互動,或者當時電腦環境沒有瀏覽器軟體的環境下,可以透過使用者帳號與密碼的方式,取得存取權杖 Access Token。因此,請先建立一個名為 MicrosoftGraphAPI 的 Console 專案,在這裡使用的是 .NET Framework 開發框架。並且把這篇文章 使用 MSAL.NET 的 Resource Owner Password Credential ROPC 架構來取得存取權杖但是無須透過瀏覽器來進行身分驗證 中的所有程式碼複製一分到這個專案內,並且使其可以正常運作。

安裝 Microsoft.Graph NuGet 套件

接著要來安裝 Microsoft.Graph 套件
  • 滑鼠右擊此專案
  • 選擇 [管理 NuGet 套件] 選項
  • 點選瀏覽標籤頁次
  • 在搜尋文字輸入盒內輸入這個文字 Microsoft.Graph
  • 點選 安裝 按鈕

開啟該使用者的 Office 365 Outlook 的行事曆

首先,先來確認這個使用者的行事曆中,是沒有任何事件或者約會存在

開始設計新增一筆行事曆事件的程式碼

請在獲取 Access Token 之後的程式碼,建立一個型別為 GraphServiceClient 的執行個體,在這裡會在建構函式內傳入一個 DelegateAuthenticationProvider 物件,並且在此要指定剛剛取得的 Access Token 存取權杖值。
使用 底下的程式碼,建立一個 Event 物件,使其加入到這個使用者的行事曆內。
await graphServiceClient.Me.Events.Request(requestOptions)
                .AddAsync(new Event
                {
                    Subject = "自動同步行事曆測試" + Guid.NewGuid().ToString(),
                    Start = startTime,
                    End = endTime
                });
請執行這個應用程式,確認有看到 新的行事曆事件已經建立成功 文字顯示出來。
最後,請檢查該使用者 Outlook 行事曆中,是否有這筆新事件產生出來。
這是這篇文章使用到的程式碼
C Sharp / C#
class Program
{
    static string clientId = "應用程式 (用戶端) 識別碼";
    static string authority = "目錄 (租用戶) 識別碼";
    static string account = "Office 365 使用者的電子郵件信箱";
    static string password = "Office 365 使用者的密碼";

    static void Main(string[] args)
    {
        GetMicrosoftGraphAccessTokeyAsync().Wait();
    }

    static async Task GetMicrosoftGraphAccessTokeyAsync()
    {
        string[] scopes = new string[] { "user.read" };
        IPublicClientApplication app;
        app = PublicClientApplicationBuilder.Create(clientId)
              .WithAuthority($"https://login.microsoftonline.com/{authority}")
              .Build();

        AuthenticationResult result = null;

        try
        {
            #region 將所提供的密碼,使用 SecureString 以加密的方式儲存
            // SecureString 代表應該將文字保密,例如於不再使用時將它從電腦記憶體刪除。 
            var securePassword = new SecureString();
            foreach (char c in password)
                securePassword.AppendChar(c);
            #endregion

            // 使用使用者的帳號與密碼憑證,來獲取存取權杖
            result = await app.AcquireTokenByUsernamePassword(scopes, account, securePassword)
                               .ExecuteAsync();
        }
        catch (MsalException ex)
        {
            Console.WriteLine(ex.Message);
        }

        Console.WriteLine(result.Account.Username);
        Console.WriteLine($"Access Token : {result.AccessToken}");
        foreach (var item in result.Scopes)
        {
            Console.WriteLine($"Scope :{item}");
        }


        var graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) =>
        {
            requestMessage
                .Headers
                .Authorization = new AuthenticationHeaderValue("bearer", result.AccessToken);

            return Task.FromResult(0);
        }));

        List<Option> requestOptions = new List<Option>();

        // 指定事件開始與結束時間
        DateTimeTimeZone startTime = new DateTimeTimeZone
        {
            DateTime = DateTime.Now.AddDays(3).ToString("o"),
            TimeZone = TimeZoneInfo.Local.Id
        };
        DateTimeTimeZone endTime = new DateTimeTimeZone
        {
            DateTime = DateTime.Now.AddDays(5).AddHours(1).ToString("o"),
            TimeZone = TimeZoneInfo.Local.Id
        };


        // 新增這個事件
        Event createdEvent = await graphServiceClient.Me.Events.Request(requestOptions)
            .AddAsync(new Event
            {
                Subject = "自動同步行事曆測試" + Guid.NewGuid().ToString(),
                Start = startTime,
                End = endTime
            });

        if (createdEvent != null)
        {
            Console.WriteLine($"新的行事曆事件已經建立成功");
        }

    }
}



使用 MSAL.NET 的 Resource Owner Password Credential ROPC 架構來取得存取權杖但是無須透過瀏覽器來進行身分驗證

使用 MSAL.NET 的 Resource Owner Password Credential ROPC 架構來取得存取權杖但是無須透過瀏覽器來進行身分驗證

更多資訊請點選 : Microsoft 驗證程式庫 (MSAL) 概觀

當想要設計一個系統服務或者要在如 IoT 的環境下,設計一個身分驗證服務,並且接著可以呼叫 Microsoft Graph 所提供的相關 API,將會遇到這樣的問題,因為當要為某個使用者進行身分驗證並且取得 Access Token 存取權杖的時候,因為當時的環境沒有或者無法使用瀏覽器,因此,將會變成不可行;那麼,究竟要如何來解決此一問題呢?這裡的需求那就是想要設計一個程式,他是在背景執行,可以幫使用者,代表該使用者來存取 Office 365 中的相關服務,例如:可以存取行事曆、可以存取信箱內的郵件、或者可以代表某個使用者來發送電子郵件。
想要能夠解決這樣的問題,在這篇文章中,將會使用 Microsoft identity platform 也就是 Microsoft 身分識別平台 (前身為適用於開發人員的 Azure Active Directory) 來進行取得所需要的 Access Token,在官方網站的定義說明為: Microsoft 身分識別平台是 Azure Active Directory (Azure AD) 開發人員平台的演化。 它可讓開發人員建置應用程式以登入所有 Microsoft 身分識別,並取得權杖以呼叫 Microsoft Graph 等 Microsoft API,或開發人員所建置的 API。若對於這個平台所提供的技術還不太孰悉的話,可以參考 Microsoft identity platform 這裡的相關說明文件內容。
大部分的時候,在要進行身分驗證過程,將會使用 OAuth 2.0 和 OpenID Connect 的方式,此時,將會需要透過瀏覽器的幫忙,由使用者輸入其身分憑證,也就是帳號與密碼。
此時,開發者將會需要知道 Microsoft 身分識別平臺支援資源擁有者密碼認證 ROPC 這個技術,授與 讓應用程式可以直接處理其密碼來登入使用者。 ROPC 流程需要高程度的信任和使用者暴露, 而且您應該只在有其他、更安全的流程無法使用時, 才使用此流程。
為了要解決之前提到的需求,將會分成兩篇文章,在這裡,第一篇文章中將會先來說明如何透過使用者的帳號與密碼,就背景取得 Microsoft Graph 的 Access Token,在下一篇文章中 使用 Microsoft.Graph 來存取 Office 365 行事曆的功能,將會說明如何透過這裡取得的 Access Token 來呼叫 Office 365 的相關功能。
在這篇文章所提到的專案原始碼,可以從 GitHub 下載

建立測試專案

在這篇文章中,將會使用一個 Console 主控台應用程式類型的專案,來進行設計這樣的需求,也就是說,在無需與使用者互動,或者當時電腦環境沒有瀏覽器軟體的環境下,可以透過使用者帳號與密碼的方式,取得存取權杖 Access Token。因此,請先建立一個名為 ROPCAuthentication 的 Console 專案,在這裡使用的是 .NET Framework 開發框架。

安裝 MSAL.NET NuGet 套件

接著要來安裝 Microsoft.Identity.Client 套件,如此,開發者無須涉入複雜與繁瑣的 HTTP 通訊協定,就可以使用 MSAL.NET 這個套件所提供的 API,就可以獲得通過身分驗證之後的存取權杖。
  • 滑鼠右擊此專案
  • 選擇 [管理 NuGet 套件] 選項
  • 點選瀏覽標籤頁次
  • 在搜尋文字輸入盒內輸入這個文字 Microsoft.Identity.Client
  • 點選 安裝 按鈕

建立 Azure Active Directory 的應用程式

現在使用的 Microsoft 身分識別平台 (v2.0),想要使用這樣的服務,就需要 使用 Microsoft 身分識別平台來註冊應用程式,因此,請準備好一個 Office 365 的帳號與密碼,準備來建立此應用程式。
請使用瀏覽器開啟 App registration 這個網址,這樣將會看到如下圖的畫面,當然,也可以直接進入到 Microsoft Azure 網頁中,在最左邊的功能清單中,找到 [Azure Active Directory] 這個選項並且點選他,也會看到相同的網頁內容。
  • 請點選 [新增註冊] 按鈕連結
  • 此時將會顯示 [註冊應用程式] 畫面
  • 請在名稱欄位輸入: 我的自動帳密登入
    該名稱為這次要設計的應用程式名稱,當然,開發者可以輸入任何可以代表這個應用程式的代表名稱
  • 對於 [支援的帳戶類型]
    請選擇 [僅此組織目錄中的帳戶 (僅 VulcanLab - 單一租用戶)] 這個選項
  • 最後請點選 [註冊] 按鈕
  • 整個操作過程如同底下螢幕截圖所示

設定 Azure Active Directory 的應用程式

現在需要把剛剛建立的應用程式進行相關設定,以滿足當初需求,此時,瀏覽器的畫面應該會顯示到剛剛建立的應用程式設定畫面上,類似下圖的螢幕截圖。
在這裡將會需要點選 [概觀] 、 [驗證] 、 [API 權限] 這三個標籤頁次,分別來進行操作
  • 請點選 [概觀] 標籤頁次
  • 在其右邊將會看到 [應用程式 (用戶端) 識別碼] 與其底下的一串 GUID 代碼
    請將這個代碼妥善儲存到適當的地方,等下寫程式的時候會用到
  • 在其右邊將也會看到 [目錄 (租用戶) 識別碼] 與其底下的一串 GUID 代碼
    請將這個代碼妥善儲存到適當的地方,等下寫程式的時候會用到
  • 請點選 [驗證] 標籤頁次
  • 將右半部畫面內容,使用滑鼠捲動到最下方
  • 此時將會看到 [預設用戶端類型] 設定
  • 請將該設定項目切換成為 [是] 選項
  • 最後點選上方的 [儲存] 按鈕
  • 請點選 [API 權限] 標籤頁次
  • 將會看到如下圖的 API 權限畫面
  • 在右半部下方的有個 [代表 VulcanLab 授予管理員同意] 的按鈕,現在是灰色的,這部分的操作等下會在後便有說明。
  • 請點選右半部上方的 [新增權限] 按鈕
  • 當 [要求 API 權限] 畫面出現之後
  • 請使用滑鼠稍微往下捲動,直到看到 Microsoft Graph 選項出現,如下面截圖
  • 請點選 [Microsoft Graph] 這個項目
  • 當出現了 委派的權限 (您的應用程式必須是登入的使用者身分,才能存取 API。) 與 應用程式權限 (您的應用程式正以背景服務或精靈執行,而且不是登入的使用者身分。) 兩個選項
  • 請點選 [委派的權限]
  • 現在將會出現所有 Microsoft Graph API 可以選用的權限清單
  • 請在 [選取權限] 下方的文字輸入盒輸入: Calendar
  • 如此,將會看到與 Office 365 行事曆相關的 API 出現
  • 在此需要點選 [Calendars.ReadWrite] 這個選項
  • 最後,點選 [新增權限] 按鈕
  • 完成這個應用程式的所有設定步驟
不過,現在螢幕畫面的最上方出現了 Permissions have changed, please wait 10 seconds before granting admin consent. Users and/or admins will have to consent even if they have already done so previously. 這段文字,看樣子是剛剛建立與設定的應用程式,需要通過管理者的同意才能夠使用。
為了要解決此一問題,此時需要請具有 Office 365 內擁有 Global Admin 權限的人幫忙處理。請管理者先登入到 Office 365 的系統上,接著請使用瀏覽器開啟 App registration 這個網址
當 Azure 網頁顯示出來之後,請點選左方的 [應用程式註冊] 選項,如此就會在右方看到剛剛建立的應用程式。
請點選這個應用程式項目
接著點選左邊清單選項中的 [API 權限] ,現在將會看到最下方的 [代表 VulcanLab 授與管理者同意] 按鈕不再是灰色的了
請點選 [代表 VulcanLab 授與管理者同意] 這個按鈕
當出現對話窗,顯示這樣內容
要代表 VulcanLab 中的所有帳戶對要求的權限授與同意嗎? 這會更新此應用程式現有的系統管理員同意記錄,以與下列記錄吻合。
請點選 [是] 按鈕
此時,在右半部的上方,將會顯示出 已成功對要求的權限授與系統管理員同意 文字,並且在 API/權限名稱 清單中,將會看到 Calendars.ReadWrite API 權限已經在清單內,最後則是狀態欄位中,看到亮起綠燈,顯示出 已授與 VulcanLab 文字,這表示了這個 API 已經可以使用了。

開始設計獲取 Token 的程式碼

想要透過 Microsoft identity platform 獲取到 Access Token ,使這個應用程式可以呼叫 Microsoft Graph 相關 API,在這裡將會是要存取指定使用者的行事曆,並且無須透過瀏覽器網頁來進行身分驗證,可以透過底下的程式碼來做到。
在程式一開始,需要先來定義四個參數,那分別是
  • clientId : 請將建立這個應用程式時候,所看到的 [應用程式 (用戶端) 識別碼] 內容填入到這個變數
  • authority : 請將建立這個應用程式時候,所看到的 [目錄 (租用戶) 識別碼] 內容填入到這個變數
  • account : Office 365 使用者的電子郵件信箱
  • password : Office 365 使用者的密碼
設定完成之後,就可以使用 PublicClientApplicationBuilder.Create 方法來產生出一個 IPublicClientApplication 的執行個體 app;接下來,需要將所提供的密碼,使用 SecureString 以加密的方式儲存,最後將會使用 app.AcquireTokenByUsernamePassword 方法,採用將使用者帳號與密碼的資訊方式,進行獲取存取權杖的動作。
若成功獲得的存取權杖,將會回傳一個非空值的 AuthenticationResult result 物件,而該物件的 Account.Username 就是這個登入驗證成功的使用者電子郵件信箱,而 AccessToken 屬性將會是我們想要取得的存取權杖。
該存取權杖是一個 JWT 的 Token,透過 jwt.io 網站來解碼解析出這個 Token,將會看到類似底下的內容。
{
  "aud": "00000003-0000-0000-c000-000000000000",
  "iss": "https://sts.windows.net/0e...........b/",
  "iat": 1568871825,
  "nbf": 1568871825,
  "exp": 1568875725,
  "acct": 0,
  "acr": "1",
  "aio": "42FgYFin+P+gdmXXvoKbcdF7J839FvaA673cbVvu5TKlYhsNJRsA",
  "amr": [
    "pwd"
  ],
  "app_displayname": "我的自動帳密登入",
  "appid": "32b..........a7",
  "appidacr": "0",
  "family_name": "account",
  "ipaddr": "1.......1",
  "name": "account",
  "oid": "222381e8-d70a-4918-971a-2ece91be672e",
  "platf": "3",
  "puid": "100320006E98B137",
  "scp": "Calendars.ReadWrite User.Read profile openid email",
  "sub": "YRgQR-gtHrtY_vGaxA_LzC_O5n8Dfs_YvEJgCSMiMAo",
  "tid": "0e..........db",
  "unique_name": "account@MyVulcan.onmicrosoft.com",
  "upn": "account@MyVulcan.onmicrosoft.com",
  "uti": "emLgFi0oVUGaQ6LmjXdXAA",
  "ver": "1.0",
  "xms_st": {
    "sub": "MD3a8TYO3PvHerAmzQyLxoMBZ5hcAJWB80pNUSUueuo"
  },
  "xms_tcdt": 1568696878
}
這是這篇文章使用到的程式碼
C Sharp / C#
class Program
{
    static string clientId = "應用程式 (用戶端) 識別碼";
    static string authority = "目錄 (租用戶) 識別碼";
    static string account = "Office 365 使用者的電子郵件信箱";
    static string password = "Office 365 使用者的密碼";

    static void Main(string[] args)
    {
        GetMicrosoftGraphAccessTokeyAsync().Wait();
    }

    static async Task GetMicrosoftGraphAccessTokeyAsync()
    {
        string[] scopes = new string[] { "user.read" };
        IPublicClientApplication app;
        app = PublicClientApplicationBuilder.Create(clientId)
              .WithAuthority($"https://login.microsoftonline.com/{authority}")
              .Build();

        AuthenticationResult result = null;

        try
        {
            #region 將所提供的密碼,使用 SecureString 以加密的方式儲存
            // SecureString 代表應該將文字保密,例如於不再使用時將它從電腦記憶體刪除。 
            var securePassword = new SecureString();
            foreach (char c in password)     
                securePassword.AppendChar(c);  
            #endregion

            // 使用使用者的帳號與密碼憑證,來獲取存取權杖
            result = await app.AcquireTokenByUsernamePassword(scopes, account, securePassword)
                               .ExecuteAsync();
        }
        catch (MsalException ex)
        {
            Console.WriteLine(ex.Message);
        }

        Console.WriteLine(result.Account.Username);
        Console.WriteLine($"Access Token : {result.AccessToken}");
        foreach (var item in result.Scopes)
        {
            Console.WriteLine($"Scope :{item}");
        }
    }
}

更多資訊請點選 : Microsoft 驗證程式庫 (MSAL) 概觀