摘要:為元件加入授權檢查的保護
如果你是商業元件的設計師,可能會希望在元件裡面加入適當的保護,以檢查使用你的元件 的用戶是否為合法授權的用戶。.NET framework 提供了一個固定的元件授權檢查模型,只要依照此模型來設計,就能很容易為元件加入授權檢查的機制。這個模型主要是依靠兩個類別,一個是 LicenseManager,另一個是 LicenseProvider 類別。其元件模型如下圖:
你在自己的元件中(通常是在建構函式裡面)呼叫 LicenseManager 的 Validate 方法,取得一個 License 物件,如果 Validate 方法傳回 null 或者丟出一個例外,就代表授權檢查失敗。而 LicenseManager 的 Validate 方法則是去呼叫 LicenseProvider 的 GetLicense 方法來取得 License 物件,因此,真正檢查元件授權的動作,是寫在 GetLicense 方法裡面。不過,LicenseProvider 是一個抽象類別,無法直接使用,你必須從這個類別繼承一個新的類別,並且改寫 GetLicense 方法,以提供檢查授權的實作程式碼。
.NET framework 提供了一個現成的 LicenseProvider 範例實作,其類別名稱是 LicFileLicenseProvider,這個類別只是供示範或測試用的,不能真的使用在實際的專案中。這裡我用一個簡單的範例,說明如何設計自己 的 LicenseProvider 類別,以提供自訂的授權檢查機制。
設計步驟
- 撰寫你自己的 LicenseProvider 類別,以提供自訂的授權檢查規則。
- 將 LicenseProvider attribute 套用到你想要保護的類別上,套用此 attribute 時,要傳入你自己的 LicensePovider 類別。
- 在你的類別裡面宣告一個私有的 License 型別的變數,用來持有授權物件。
- 呼叫 LicenseManager 的 Validate 方法或者 IsValid 屬性,以判斷元件的使用者是否有獲得授權。
實作步驟
(a) 建立元件
- New 一個 Class Library project: MyLib。
- 刪除既有的 Class1.cs,加入一個類別: MyTextBox.cs。
- 加入組件參考:System.Windows.Forms.dll。
- 讓 MyTextBox 類別繼承自 System.Windows.Forms.TextBox。
- Build 專案。
以上只是撰寫元件的一般程序,並沒有特別之處,稍後我們會再回來為這個類別加上授權檢查機制。
(b) 撰寫自己的 LicenseProvider 類別
- 在 MyLib 專案中加入一個類別: MyLicenseProvider.cs。
- 修改 MyLicenseProvider.cs,如下:
using System; using System.ComponentModel; using System.IO; using System.Reflection; namespace MyLib { public class MyLicenseProvider : LicenseProvider { public MyLicenseProvider() { } public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions) { /* * 利用 context 參數的 UsageMode 屬性來判斷目前是在 * 設計時期,還是在執行時期. 這裡我們只在設計時期才 * 檢查元件的授權. */ if (context.UsageMode == LicenseUsageMode.Designtime) { // 只單純的檢查元件所在的路徑是否有一個 MyLic.txt 檔案, // 有的話就表示合法授權. FileInfo fi = new FileInfo(Assembly.GetExecutingAssembly().FullName); string fname = fi.DirectoryName + @"\MyLic.txt"; fi = new FileInfo(fname); if (fi.Exists) { return new MyLicense(); } else { if (allowExceptions) { throw new Exception("您尚未取得使用此元件的合法授權,請向 XX 公司洽詢!"); } return null; } } else // 不需要檢查授權 { return new MyLicense(); } } } // 實作你自己的 License 物件 public class MyLicense : License { public override string LicenseKey { get { // 你應該修改這個實作,以提供應用程式唯一的授權碼 return "123"; } } public override void Dispose() { } } }
在這個檔案裡面有兩個類別:MyLicenseProvider 和 MyLicense。檢查元件是否為合法授權的程式碼主要是放在 MyLicenseProvider 的 GetLicense 方法裡面。當 GetLicense 的檢查授權動作確認元件是合法授權使用,便會傳回一個 MyLicense 的物件實體,否則會丟出一個例外,或者傳回 null(端看參數 allowExceptions 是否為 true 而定)。在 GetLicense 裡面,首先判斷 context 參數的 UsageMode 屬性,當此屬性的值為 LicenseUsageMode.Designtime 時才進行授權檢查,也就是說,只有在設計時期才進行檢查,執行時期則不檢查。如果你需要控制檢查授權的時機,只要修改這部份的程式碼就行了。
由於我們不能直接建立 License 抽象類別的實體,因此定義了 MyLicense 類別,來建立我們自己的 License 物件。通常你會把授權的相關資訊(例如:應用程式或使用者的授權碼)保存在這個 License 物件裡面,這裡只做個簡單的示範,因此沒有做進一步的處理。根據實際需求的複雜程度,你甚至可以從 License 類別繼承下來兩個不同的類別,分別作為設計時期和執行時期的 License 物件,例如:MyDesigntimeLicense 和 MyRuntimeLicense。
(c) 為元件加上授權檢查
- 在 MyTextBox.cs 中加入 using System.ComponentModel;
- 在 MyTextBox 類別宣告前面加上 LicenseProvider attribute:
[LicenseProvider(typeof(MyLicenseProvider))] public class MyTextBox : TextBox
- 在 MyTextBox 類別中加入一個私有成員變數:
private MyLicense lic;
- 在 MyTextBox 建構函式中利用 LicenseManager 進行授權檢查的動作::
public MyTextBox() { lic = (MyLicense) LicenseManager.Validate(typeof(MyTextBox), this); }
- 修改 MyTextBox 的 Dispose 方法,以便釋放 MyLicense 物件,如下:
protected override void Dispose( bool disposing ) { if( disposing ) { if (lic != null) { lic.Dispose(); lic = null; } } base.Dispose( disposing ); }
- Build 專案。
- 將元件註冊到 Toolbox。作法為:點選 Tools | Add/Remove Toolbox Items,點 Browse 鈕,然後選擇 MyLib.dll,按 OK。
(d) 建立測試專案
- New 一個 Windows Application 專案:MyApp。
- 從 Toolbox 中把 MyTextBox 拖到 form 上面,此時應該會出現錯誤 "您尚未取得使用此元件的合法授權,請向 XX 公司洽詢",而且控制項無法建立在 form 上面。
- 接著在 MyLib 專案的輸出路徑底下建立一個文字檔,檔名為 "MyLic.txt",內容不拘,只要有這個檔案就行了。註:因為 MyLicenseProvider 的 GetLicense 方法只判斷元件所在的目錄下是否有 MyLic.txt 這個檔案,有的話就視為合法授權使用。
- 再從 Toolbox 中把 MyTextBox 拖到 form 上面,此時應該可以通過授權檢查,而且控制項可以建立在 form 上面。
- 接著測試執行時期是否會檢查元件的授權。先 Build MyApp 專案,然後將步驟 3 所建立的 MyLic.txt 檔案刪除掉,接著利用檔案總管直接執行 MyApp.exe,應用程式應該可以正常執行。這表示執行時期並沒有檢查元件的授權,因為在 MyLicenseProvider 的 GetLicense 方法裡面,我們判斷了 context 參數的 UsageMode 屬性,只有當此屬性為 LicenseUsageMode.Designtime 時才進行授權檢查。
Ok! 大概就這樣了,只要您了解 LicenseManager 和 LicenseProvider 之間的關係,以及如何實作自己的 LicenseProvider 類別,應該很容易就能夠根據自己的需求做出不同的變化了。