使用ASP開發(fā)NT目錄服務會出現(xiàn)的一些問題(I)
有關ADSI的資料真是難找,技術雖然很好,可惜300多頁的SDK我可真看不動 要是哪位大俠有空的話,能夠幫我翻譯就好了,呵呵。 現(xiàn)在只好將就著翻譯一些短小的文章了,哎。匆忙之間翻譯成的,錯誤肯定不 少,還希望大家諒解。 使用到的技術還是我前面提到的ADSI,這一節(jié)的重點放在操縱目錄樹上。 目錄服務(DN)在貫穿了整個NT領域。幾乎每一個管理任務最終都會 去改變系統(tǒng)目錄中的某一個目錄。象加入新用戶到組里面,新建一個 互聯(lián)網網站,或則更新電子郵件目錄等等。注意的是,Windows2000 的活動目錄已經支持這個技術。 微軟已經提供了一些功能很強大的COM接口來訪問不同的目錄服務。 ADS 命名空間和provider ADS provider的概念和ODBC結構很相象,例如Oracle的ODBC驅動器讓一臺機器連接到 Oracle的數(shù)據(jù)庫中,但是這并不意味著這個數(shù)據(jù)庫確實存在。 同樣的關系也使用與ADSI,它是一個適用與不同的目錄命名空間的公共接口。 也許這個目錄命名空間存在與網絡中。 在一個典型的服務器上,當安裝了正確的工具箱后,你會找到三個ADS provider 他們是: WinNT: - 給NT及其網絡用的 IIS: - 給IIS用的 LDAP: - 給MS Exchange和Windows200的活動目錄用的 也許你還會發(fā)現(xiàn)下面的provider NWCOMPAT: - 給Novell 3.1用的 NDS: - 給Novell Directory Services用的 每一個命名空間對象都由目錄服務的根節(jié)點集組成,典型的例子是 NT的domain或者server,但不是所有的provider都能夠自動發(fā)現(xiàn)根目錄節(jié)點。 你能夠綁定到一個WinNT:對象上它會提供一個NT域列表 但是對于IIS和LDAP的命名空間對象,則既沒有IIS也沒有MS Exchange的根節(jié)點. 在使用的時候而必須要被指明。
容器,會員,集合 對于大部分而言,目錄是一個分層目錄結構的對象同時它還包容了其他的對象 舉例來說,一個物理的IIS服務器有多個網站,每個網站還可以有多個目錄( 或則網站的運用程序),而這些目錄還有子目錄。 一個NT的domain能夠有多個服務器等等。
在ADSI術語中,所有上面的容器對象又包容其它對象,就組成了命名空間樹。 典型的代碼如下: Set oAds = GetObject("WinNT://MyDomain")
For Each oAdsChild in oAds
' do something
Next
分層目錄模型并不能夠完全描述對象之間的關系。個別而言,NT的用戶和組對象 約束與Domain 和 Server對象,但是他們之間又有一個附加的會員關系。 ADSI對象模型通過.Groups和.Menmbers屬性來表示會員關系 例如一個典型的列表如下: Set oAds = GetObject("WinNT://MyDomain/Administrator") For Each oAdsGroup in oAds.Groups ' do something Next ' ... Set oAds = GetObject("WinNT://MyDomain/Domain Users") For Each oAdsMember in oAds.Members ' do something Next 仔細觀察上面的代碼的微妙的不同之處 對一個對象本身執(zhí)行列表,將返回它的子層。 對一個對象的.Member屬性執(zhí)行列表將返回它的會員列表。 最后,還有一些動態(tài)集合來表示那些暫時獨立的對象。 一個典型的例子是在打印隊列中的任務.PrintJobs集合
Schema對象 每個ADS對象都聯(lián)系在一個SCHEMA對象,來表示它的性能和特征 我們在寫代碼的時候經常碰到這樣的問題:我的對象到底支持那些屬性 這是一個容器對象,或則對象有可能包含什么樣的類型。 例如,在原則上,一個目錄服務本身就是一個徹底的SCHEMA對象。
準備運行程序 這個ADS瀏覽程序需要有一定的安全權限才能夠運行。 拷貝這個ADS瀏覽文件到你的網絡中的一個共享的目錄中 映射一個虛擬的web目錄 指派這個目錄有管理者的權限。
看一看命名空間樹
在這里使用了微軟的HtmlHelp Java applet. 它能夠產生我們需要的樹狀結構。尤為重要的是它能夠提供對子樹的支持 因為我并不愿意拿我的整個目錄樹來冒險。 一個有關HtmlHelp applet的討論會遠遠超出現(xiàn)在的話題,下面就只給出很簡短的版本: <UL> <!-- ... --> <LI>IIsWebServer Objects <UL> <LI> 1 <!-- on click: 顯示頁面 AdsProperties.asp?AdsPath=IIS://myserver/W3SVC/1} --> <UL> <!-- on expand: 顯示下一級 AdsTreeHhc.asp?AdsPath=IIS://myserver/W3SVC/1 --> </UL> <LI> 2 <!-- on click: 顯示頁面 AdsProperties.asp?AdsPath=IIS://myserver/W3SVC/2} --> <UL> <!-- on expand: 顯示下一級 AdsTreeHhc.asp?AdsPath=IIS://myserver/W3SVC/2 --> </UL> <!-- ... --> </UL> <!-- ... --> </UL>
怎么找到目錄樹的節(jié)點 程序流程應該如下: 1。綁定到一個目錄對象 2。查找與之關聯(lián)的schema類 3。如果它是一個容器對象,那么 For all 可能的容器 in 這個對象 (通過schema得到) 對所有的對象進行實現(xiàn) 使用HtmlHelp applet生成<LI>... 在實現(xiàn)過程中,其實一共才10行代碼,但是每一行代碼都有起自己的難點 掌握了它們你就能夠實現(xiàn)很多其它美妙的功能。
難點一:查找Schema類對象 第一個難點就是并不是所有的ADS對象都有真正有一個schema. 一段程序段如下 Set oAds = GetObject(vAdsPath) Set oAdsClass = GetObject(oAds.Schema) 對于一些高一級的對象來說這段代碼將會失敗.必須再加一點異常處理。 Function GetClass(oADs) On Error Resume Next Set GetClass = Nothing Set GetClass = GetObject(oADs.Schema) End Function Set oAdsClass = GetClass(oAds) If Typename(oAdsClass) <> "Nothing" Then ' do something End If
通過管理一個schema類,我們查看它的.Container屬性來決定我們處理的容器類型。 接著當我們使用它的.Containment數(shù)組來得到對象的類。 舉例來說,一些Domain對象將返回一個schema類數(shù)組,其中包含有 字符串"Computer", "User", "Group", 和 "Schema". 理論上的代碼如下 If oAdsClass.Container Then vContainment = oAdsClass.Containment For vIdx=0 to uBound(vContainment) oAds.Filter = Array(vContainment(vIdx)) For Each oAdsChild in oAds ' write an <LI>... entry Next Next End If 但是又出現(xiàn)問題了,這個方法有時候不能夠工作。一個WinNT Domain的.Containment數(shù)組 僅僅返回本來是4個對象類中的3個.而LDAP的provider根本就不執(zhí)行.Container和.Containment屬性 這樣我們就沒法再使用上面的代碼了,只好針對這些怪異的現(xiàn)象造出一些怪異的代碼了 其它奇怪的地方 下面是一些很怪異的代碼,例如NT的LanmanServer對象可以想象它應該有一個FileService 類 并且包含有一個FileShare類對象.正確的代碼如下: Set oAds = GetObject("WinNT://MyDomain/MyServer/LanmanServer") 但是很不幸的是當我們調用它的父節(jié)點時將會出錯 Set oAds = GetObject("WinNT://MyDomain/MyServer") oAds.Filter = Array("FileService") For Each oAdsChild in oAds ' 這里的代碼將永遠不會執(zhí)行 Next 下面類似的辦法也會出錯: Set oAds = GetObject("WinNT://MyDomain/MyServer") For Each oAdsChild in oAds If oAdsChild.Name = "LanmanServer" Then For Each oAdsGrandChild in oAdsChild ' 出錯 Next End If Next 這是為什么呢,其實LanmanServer有一個雙重身份.它是一個FileService對象 但同時它也是一個普通的Service對象。所以下面這段怪異的代碼就產生了: For Each oAdsChild in oAds If oAdsChild.Name = "LanmanServer" Then Set oAdsChild = GetObject(oAdsChild.AdsPath) For Each oAdsGrandChild in oAdsChild ' 終于成功了 Next End If Next
對象性質: 同上面相比,對象的屬性相對容易獲得。每個對象可以想象得到都有一個核心的屬性。 比如name,通過這個相同的屬性能夠很容易的使用對象: vAdsName = oAds.Name 大多數(shù)對象還有這樣的屬性.MandatoryProperties 和 .OptionalProperties , 這都能夠通過他們 的schema類得到,它們的數(shù)值可以通過對象的.GetEx方法得到: For Each vProp in oAdsClass.MandatoryProperties vPropValue = oAds.GetEx(vProp) Next
|