第一,在局域网内,如何管理计算机上的资源,须要一个管理策略。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(); } }