第一,在局域網內,如何管理計算機上的資源,需要一個管理策略。
微軟提供了兩種:工作組和域。兩者區別就是,工作組是自治的,組內的計算機個個都作為獨立、對等的自治實體而存在。恩,這也是以太網的設計初衷。
但是,當我們需要額外的管理模型,其實作為一個組織,更可能的是,需要一個公共的中央控制主機,這就是域模型。域模型中,會提供一個域控制器,域控制器上存儲了這個域內的所有賬戶信息,也就是一個賬戶數據庫Active Directory。這也就導致,資源、賬戶、機器的概念開始分離。
第二,在域管理中,正常的思路是,基於域名來定位機器,那么首先第一條就是建立DNS記錄,或者安裝DNS服務器。
然后在創建Active Directory時,其實是從 這個域名***.com開始,讓***.com成為一個域的起始節點,術語是“新林中域”,因為從邏輯上將按照ldap的方法,現有域林,然后又域,最后才有域。
第三,創建好之后,我們就來看一下這個active directory數據庫能放哪些數據:

表結構看不到,那看一下文件結構吧:
Active Directory 是一個事務處理數據庫系統,它使用日志文件來支持回滾語法,從而確保將事務提交到數據庫中。與 Active Directory 關聯的文件包括: Ntds.dit — 數據庫。 Edbxxxxx.log — 事務日志。 Edb.chk — 檢查點文件。 Res1.log 和 Res2.log — 預留的日志文件。 Ntds.dit 會隨着數據庫的填充而不斷增大。但是,日志的大小卻是固定的 (10 MB)。對數據庫進行的任何更改都會被追加到當前的日志文件中,而且其磁盤映像會不斷保持更新。 Edb.log 是當前的日志文件。對數據庫進行更改后,會將該更改寫入到 Edb.log 文件中。當 Edb.log 文件充滿事務之后,它會被重新命名為 Edbxxxxx.log。(從 00001 開始,並使用十六進制累加。) 由於 Active Directory 使用循環記錄,所以在舊日志文件寫入數據庫之后,這些舊日志文件會及時刪除。在任何時刻都可以找到 edb.log 文件,而且還可能有一個或多個 Edbxxxxx.log 文件。 Res1.log 和 Res2.log 是“占位符”— 用來在此驅動器上預留(在此情況下)最后的 20 MB 磁盤空間。這是為了給日志文件提供足夠的空間,以便在其它所有磁盤空間都已使用的情況下可以正常關機。 Edb.chk 文件存儲數據庫的檢查點,這些檢查點標識數據庫引擎需要重復播放日志的點,通常在恢復或初始化時。 出於性能考慮,日志文件應該位於數據庫所在磁盤以外的其它磁盤上,以減少磁盤爭用情況。 在進行備份時,可能會創建新的日志文件。如前所述,由於要進行循環記錄,所以需要刪除該日志文件(如常規舊日志文件)。 幾個非常有用的AD維護工具:ntdsutil.exe; ldp.exe; dcdiag.exe; adsiedit.exe; netdom.exe; replmon.exe; dssite.msc; repadmin.
第四,就是在這個域系統中,是如何進行認證的呢,簡單的密碼和用戶顯然,太單薄了。這里的解決方式是電子令牌。
第五,備份。windows的備份工具是一體的,但是你可以選擇備份的內容,就是單獨把active directory備份出來。
第六,就是基於如ad域這樣的ldap服務器,和普通的數據庫表內容存取賬戶信息之間的性能差異有多少呢?恩,據說,當數據量達到上萬時,會很可觀。但是我在這里采用它,則考慮的是它是作為標准協議而存在。
第七,嘗試編寫如下的深度優先遍歷函數,實現了對組織的深度優先遍歷
/** * @Description: * @comment:wuchao * @time:2015年9月10日下午1:57:52 */ package test; import java.util.Hashtable; import javax.naming.Context; import javax.naming.ldap.LdapContext; import javax.naming.ldap.InitialLdapContext; import javax.naming.NamingEnumeration; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import java.util.Enumeration; public class ADOperTest { public ADOperTest() { } public void GetADInfo() { // ldap 訪問參數設置 Hashtable HashEnv = new Hashtable(); String LDAP_URL = "ldap://192.168.1.***:389"; String adminName = "Administrator@***.cn"; String adminPassword = "****"; HashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); HashEnv.put(Context.SECURITY_PRINCIPAL, adminName); HashEnv.put(Context.SECURITY_CREDENTIALS, adminPassword); HashEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); HashEnv.put(Context.PROVIDER_URL, LDAP_URL); try { LdapContext ctx = new InitialLdapContext(HashEnv, null); SearchControls searchCtls = new SearchControls(); // onelevel 就是為了深度優先遍歷而設 searchCtls.setSearchScope(SearchControls.ONELEVEL_SCOPE); // 搜索用戶 // String searchFilter = "objectClass=User"; // 搜索組織 // String searchFilter = "objectClass=organizationalUnit"; String searchFilter = "objectClass=organizationalUnit"; // 搜索根節點 String searchBase = "OU=***,DC=***,DC=cn"; String returnedAtts[] = { "url", "whenChanged", "employeeID", "name", "userPrincipalName", "physicalDeliveryOfficeName", "departmentNumber", "telephoneNumber", "homePhone", "mobile", "department", "sAMAccountName", "whenChanged", "mail", "userPassword" }; searchCtls.setReturningAttributes(returnedAtts); int i = 0; try { NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls); System.out.println("" + i + ":" + searchBase); SearchResult sr; i++; while (answer.hasMore()) { sr = (SearchResult) answer.next(); printspace(i); System.out.print("" + i + ":" + sr.getName() + "\n"); recursiveGetChild(ctx, sr.getName() + "," + searchBase, searchCtls, searchFilter, i); } } catch (NamingException e) { e.printStackTrace(); System.err.println("Throw Exception : " + e); } ctx.close(); } catch (NamingException e) { e.printStackTrace(); System.err.println("Throw Exception : " + e); } } // 遞歸函數,遞歸輸出子組織 void recursiveGetChild(LdapContext ctx, String searchBase, SearchControls searchCtls, String searchFilter, int i) { SearchResult sr; try { NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls); i++; while (answer.hasMore()) { sr = (SearchResult) answer.next(); printspace(i); System.out.print("" + i + ":" + sr.getName() + "\n"); recursiveGetChild(ctx, sr.getName() + "," + searchBase, searchCtls, searchFilter, i); } } catch (NamingException e) { e.printStackTrace(); System.err.println("Throw Exception : " + e); } } // 格式化輸出 void printspace(int i) { while (i-- > 0) { System.out.print(" "); } } public static void main(String args[]) { ADOperTest ad = new ADOperTest(); ad.GetADInfo(); } }
結果如下:

第八,附帶輸出用戶的代碼是:
/** * @Description: * @comment:wuchao * @time:2015年9月10日下午1:57:52 */ package test; import java.util.Hashtable; import javax.naming.Context; import javax.naming.ldap.LdapContext; import javax.naming.ldap.InitialLdapContext; import javax.naming.NamingEnumeration; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import java.util.Enumeration; public class ADOperTest { // 搜索用戶 private String searchUserFilter = "objectClass=User"; public ADOperTest() { } public void GetADInfo() { // ldap 訪問參數設置 Hashtable HashEnv = new Hashtable(); String LDAP_URL = "ldap://192.168.1.***:389"; String adminName = "Administrator@***.cn"; String adminPassword = "***"; HashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); HashEnv.put(Context.SECURITY_PRINCIPAL, adminName); HashEnv.put(Context.SECURITY_CREDENTIALS, adminPassword); HashEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); HashEnv.put(Context.PROVIDER_URL, LDAP_URL); try { LdapContext ctx = new InitialLdapContext(HashEnv, null); SearchControls searchCtls = new SearchControls(); // onelevel 就是為了深度優先遍歷而設 searchCtls.setSearchScope(SearchControls.ONELEVEL_SCOPE); // 搜索組織 String searchFilter = "objectClass=organizationalUnit"; // 搜索根節點 String searchBase = "OU=***,DC=****,DC=cn"; String returnedAtts[] = { "url", "whenChanged", "employeeID", "name", "userPrincipalName", "physicalDeliveryOfficeName", "departmentNumber", "telephoneNumber", "homePhone", "mobile", "department", "sAMAccountName", "whenChanged", "mail", "userPassword" }; searchCtls.setReturningAttributes(returnedAtts); int i = 0; System.out.println("" + i + ":" + searchBase); i++; //打印用戶 try{ NamingEnumeration answer = ctx.search(searchBase, searchUserFilter, searchCtls); SearchResult sr; while (answer.hasMore()) { sr = (SearchResult) answer.next(); printspace(i); System.out.print("user " + i + ":" + sr.getName() + "\n"); } }catch(NamingException e){ e.printStackTrace(); } //打印 組織 try { NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls); SearchResult sr; while (answer.hasMore()) { sr = (SearchResult) answer.next(); printspace(i); System.out.print("" + i + ":" + sr.getName() + "\n"); recursiveGetChild(ctx, sr.getName() + "," + searchBase, searchCtls, searchFilter, i); } } catch (NamingException e) { e.printStackTrace(); System.err.println("Throw Exception : " + e); } ctx.close(); } catch (NamingException e) { e.printStackTrace(); System.err.println("Throw Exception : " + e); } } // 遞歸函數,遞歸輸出子組織 void recursiveGetChild(LdapContext ctx, String searchBase, SearchControls searchCtls, String searchFilter, int i) { SearchResult sr; i++; //打印用戶 try{ NamingEnumeration answer = ctx.search(searchBase, searchUserFilter, searchCtls); while (answer.hasMore()) { sr = (SearchResult) answer.next(); printspace(i); sr.getAttributes().get("cn"); System.out.print("user " + i + ":" + sr.getAttributes().get("sAMAccountName") + "\n"); } }catch(NamingException e){ e.printStackTrace(); } // 打印組織 try { NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls); i++; while (answer.hasMore()) { sr = (SearchResult) answer.next(); printspace(i); System.out.print("" + i + ":" + sr.getName() + "\n"); recursiveGetChild(ctx, sr.getName() + "," + searchBase, searchCtls, searchFilter, i); } } catch (NamingException e) { e.printStackTrace(); System.err.println("Throw Exception : " + e); } } // 格式化輸出 void printspace(int i) { while (i-- > 0) { System.out.print(" "); } } public static void main(String args[]) { ADOperTest ad = new ADOperTest(); ad.GetADInfo(); } }

