第一,在局域網內,如何管理計算機上的資源,須要一個管理策略。java
微軟提供了兩種:工做組和域。二者區別就是,工做組是自治的,組內的計算機個個都做爲獨立、對等的自治實體而存在。恩,這也是以太網的設計初衷。數據庫
可是,當咱們須要額外的管理模型,其實做爲一個組織,更可能的是,須要一個公共的中央控制主機,這就是域模型。域模型中,會提供一個域控制器,域控制器上存儲了這個域內的全部帳戶信息,也就是一個帳戶數據庫Active Directory。這也就致使,資源、帳戶、機器的概念開始分離。windows
第二,在域管理中,正常的思路是,基於域名來定位機器,那麼首先第一條就是創建DNS記錄,或者安裝DNS服務器。服務器
而後在建立Active Directory時,實際上是從 這個域名***.com開始,讓***.com成爲一個域的起始節點,術語是「新林中域」,由於從邏輯上將按照ldap的方法,現有域林,而後又域,最後纔有域。dom
第三,建立好以後,咱們就來看一下這個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備份出來。url
第六,就是基於如ad域這樣的ldap服務器,和普通的數據庫表內容存取帳戶信息之間的性能差別有多少呢?恩,聽說,當數據量達到上萬時,會很可觀。可是我在這裏採用它,則考慮的是它是做爲標準協議而存在。 spa
第七,嘗試編寫以下的深度優先遍歷函數,實現了對組織的深度優先遍歷
/** * @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(); } }