伴隨著.net開發(fā)技術(shù)的成熟,軟件開發(fā)進(jìn)入控件化時(shí)代。越來越多的公司投入軟件開發(fā)領(lǐng)域,企圖控制軟件產(chǎn)業(yè)鏈的上游:提供解決方案。其中一部分公司就是提供控件?丶䦟(duì)外就象是一個(gè)黑盒子,借助于方法,屬性和事件,開發(fā)人員即可輕易的開發(fā)出專業(yè)的應(yīng)用程序,與此同時(shí),軟件的保護(hù)方法也不斷出現(xiàn)。在共享軟件時(shí)代,軟件開發(fā)人員開發(fā)好程序,然后設(shè)計(jì)一個(gè)序列號(hào)生成算法,對(duì)正式許可的用戶發(fā)布序列號(hào),生成注冊(cè)文件。在應(yīng)用程序啟動(dòng)時(shí)檢查注冊(cè)文件,如果有則繼續(xù)運(yùn)行,否則中止運(yùn)行或是提供部分功能。
.net 技術(shù)的出現(xiàn),也提供了相應(yīng)的軟件保護(hù)解決方案。本文詳細(xì)討論.net 技術(shù)的軟件保護(hù)方案與實(shí)現(xiàn)。我們可以采用各種方式來生產(chǎn)許可,授權(quán)用戶使用我們開發(fā)的控件。常見的方式如下:
- 注冊(cè)表。在控件安裝時(shí),在注冊(cè)表中寫入相應(yīng)的鍵值,在控件運(yùn)行時(shí),查找該鍵,如找不到則拋出異常;
- 許可文件。在控件運(yùn)行時(shí),查找許可文件,如找不到,則拋出異常;
- 遠(yuǎn)程Web服務(wù)驗(yàn)證。在控件運(yùn)行時(shí),連接到遠(yuǎn)程的許可驗(yàn)證服務(wù)器,如能找到值,則表示已經(jīng)授權(quán);
注冊(cè)表的驗(yàn)證方式實(shí)現(xiàn)起來容易,但是也很容易發(fā)生驗(yàn)證異常。如果用戶裝有注冊(cè)表監(jiān)控程序,跟蹤對(duì)注冊(cè)表的每一項(xiàng)改動(dòng),則會(huì)很容易定位到鍵值,進(jìn)而分析和利用,此外,這種方式對(duì)XCOPY也有影響,不方便部署應(yīng)用程序;許可文件根據(jù)用戶的硬件信息,比如硬盤序列號(hào),或是MAC地址,郵件,生成一個(gè)許可文件,放在控件可以找到的地方,在運(yùn)行時(shí)找到該許可文件,如果找不到,則阻止控件的運(yùn)行;遠(yuǎn)程Web服務(wù)需用客戶端能聯(lián)網(wǎng),在控件運(yùn)行時(shí)向服務(wù)器發(fā)出查詢?cè)S可的命令,如果找不到,則停止運(yùn)行;如果用戶不聯(lián)網(wǎng),這種方式有局限性,用戶根本不能在脫機(jī)的情況下嘗試運(yùn)行該控件。
需要理解的對(duì)象:LicenseProvider
MSDN中的解釋是:提供 abstract 基類以便實(shí)現(xiàn)許可證提供程序。從 LicenseProvider 繼承時(shí),必須重寫 GetLicense 方法。我們可以理解為一個(gè)許可證的提供程序,在控件需要驗(yàn)證時(shí),提供許可授權(quán),如果不提供許可,則不能使用該控件,拋出異常。這是個(gè)抽象類,不允許實(shí)例化,我們從該類派生,并且重寫GetLicense方法。
public class FileLicenseProvider : System.ComponentModel.LicenseProvider { public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions) { if (context.UsageMode == LicenseUsageMode.Designtime) { // 開發(fā)人員設(shè)計(jì)時(shí)不需要許可,直接頒發(fā)許可證 return new FileLicense(this, "The App"); } else { string licenseFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, type.FullName+".lic"); if (File.Exists(licenseFile)) return new FileLicense(this, "The App"); else return null; } } } |
通過覆蓋GetLicense方法,我們獲取需要驗(yàn)證的控件的類型信息,然后在當(dāng)前應(yīng)用程序目錄下查找以控件的lic文件,如找到,頒發(fā)許可,否則返回null值。
License
MSDN中的解釋為:為所有許可證提供 abstract 基類。向控件的特定實(shí)例授予許可證。通俗的理解就是許可,給控件頒發(fā)的許可,表示控件已經(jīng)授權(quán)過了,可以被使用。下面的代碼可以幫助您理解許可的含義。
public class FileLicense : System.ComponentModel.License { //許可驗(yàn)證提供程序 private FileLicenseProvider owner; private string key; public FileLicense(FileLicenseProvider owner, string key) { this.owner = owner; this.key = key; } //許可Key,通俗的理解是序列號(hào)。 public override string LicenseKey { get { return key; } } public override void Dispose() { } } |
FileLicense會(huì)應(yīng)用到控件上,如果返回給控件的FileLicense為空,則控件會(huì)拋出異常。
應(yīng)用許可提供程序
開發(fā)一個(gè)控件,如何應(yīng)用許可驗(yàn)證呢?
如下代碼所示,我們開發(fā)一個(gè)MyControl的控件,同時(shí)給它加上LicenseProvider特性(attribute),這樣在該控件運(yùn)行時(shí),會(huì)用FileLicenseProvider來實(shí)行許可驗(yàn)證。
[LicenseProvider(typeof(FileLicenseProvider))] public class MyControl : WebControl |
此外,我們還需要在控件的構(gòu)造方法中進(jìn)一步調(diào)用驗(yàn)證方式:
public MyControl() { try { license = LicenseManager.Validate(typeof(MyControl), this); } catch { HttpContext.Current.Response.Write("MyControl控件未授權(quán),請(qǐng)聯(lián)系程序開發(fā)商"); } } |
如果該控件獲取正確的授權(quán),則會(huì)繼續(xù)運(yùn)行,否則因得不到許可而不能繼續(xù)生成。 LicenseManager類會(huì)找到FileLicenseProvider類的GetLicense方法,來獲取許可,經(jīng)過各種驗(yàn)證方式(注冊(cè)表,許可文件)來提供許可實(shí)例,如果驗(yàn)證失敗,則會(huì)拋出LicenseException,表示無法找到許可。
許可驗(yàn)證服務(wù)器
在注冊(cè)表驗(yàn)證方式中,我們需要在控件的安裝程序中嵌入腳本,在注冊(cè)表中寫入相應(yīng)的鍵值;在本地許可文件驗(yàn)證方式下,我們需要根據(jù)序列號(hào)生產(chǎn)相應(yīng)的許可文件;在遠(yuǎn)程Web服務(wù)的驗(yàn)證方式下,我們還需要設(shè)計(jì)一個(gè)遠(yuǎn)程的驗(yàn)證服務(wù)器,接受客戶端的驗(yàn)證請(qǐng)求。 下面我們來討論一下如何設(shè)計(jì)這個(gè)服務(wù)器應(yīng)用程序。
Web服務(wù)是跨平臺(tái)的通用協(xié)議,借助于SOAP(簡(jiǎn)單對(duì)象訪問協(xié)議),我們能接受各種平臺(tái)的驗(yàn)證請(qǐng)求。
借助于ASP.NET Web服務(wù),我們可以輕易的實(shí)現(xiàn)這個(gè)服務(wù)器端應(yīng)用。 打開Visual Studio 2008,新建ASP.NET Web Service Application
圖一 新建Web Service
把新建的服務(wù)名稱改LicenseService.asmx,然后在該服務(wù)中提供驗(yàn)證方法
[WebMethod] public bool ValidateLicense(string mac) { bool ret = Validate(mac); return ret; } |
Validate方法會(huì)去查找數(shù)據(jù)庫記錄,返回結(jié)果,提供給客戶端。 為此,我們還需要設(shè)計(jì)數(shù)據(jù)庫。
圖二 SQL設(shè)計(jì)視圖
這里,我們采用驗(yàn)證客戶端MAC地址的方式,如果能找到該地址,則把Enabled設(shè)為1,否則找不到,表示該MAC地址未授權(quán),返回false給許可驗(yàn)證提供程序。SQL 腳本如下:
CREATE TABLE [dbo].[LicenseUser]( [MAC] [varchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL, [Enabled] [smallint] NULL, CONSTRAINT [PK_LicenseUser] PRIMARY KEY CLUSTERED ( [MAC] ASC )WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] |
應(yīng)用程序
由于開發(fā)的是Web控件,我們?cè)O(shè)計(jì)一個(gè)Web站點(diǎn),來測(cè)試我們的控件保護(hù)方案。右擊解決方案,添加現(xiàn)有站點(diǎn)(Web site)
圖三 添加現(xiàn)有站點(diǎn)
把我們的控件從工具欄中拖動(dòng)到一個(gè)Web頁面中,生成應(yīng)用程序,然后F5,調(diào)試運(yùn)行。頁面的源代碼如下:
<uc:MyControl ID="MyControl1" runat="server" />
另外,在Web.config中添加如下代碼,您可以不必在每一個(gè)頁面中都加入控件引用。
<pages> <controls> <add tagPrefix="uc" namespace="HTSystem" assembly="HTSystem.Component, Version=1.1.0.0, Culture=neutral, PublicKeyToken=c2c8c99b69b1086e"/> </controls> </pages> |
您可能也注意到了,我們給自己寫的組件MyControl添加了版本和強(qiáng)命名元數(shù)據(jù),這樣可以保護(hù)我們的組件。
總結(jié)
本文試圖給您提供幾種常用的許可驗(yàn)證的方式。文中詳細(xì)討論了許可文件的驗(yàn)證方案,分析了如何借助Web服務(wù)技術(shù),設(shè)計(jì)遠(yuǎn)程驗(yàn)證服務(wù)器,另外,您還應(yīng)該了解注冊(cè)表的方式的驗(yàn)證方式。 您可以通過閱讀源代碼,詳細(xì)了解這三種方式的實(shí)現(xiàn)。