一:LDAP
LDAP是Lightweight Directory Access Protocol的縮寫,即輕量級目錄訪問協議(這個主要是相對另一目錄訪問協議X.500而言的;LDAP略去了x.500中許多不太常用的功能,且以TCP/IP協議為基礎)。目錄服務和數據庫很類似,但又有着很大的不同之處。數據庫設計為方便讀寫,但目錄服務專門進行了讀優化的設計,因此不太適合於經常有寫操作的數據存儲。同時,LDAP只是一個協議,它沒有涉及到如何存儲這些信息,因此還需要一個后端數據庫組件來實現。這些后端可以 是bdb(BerkeleyDB)、ldbm、shell和passwd等。
LDAP目錄以樹狀的層次結構來存儲數據(類同於DNS),最頂層即根部稱作“基准DN”,形如"dc=domain,dc=com"或者"o= domain.com",前一種方式更為靈活也是Windows AD中使用的方式。在根目錄的下面有很多的文件和目錄,為了把這些大量的數據從邏輯上分開,LDAP像其它的目錄服務協議一樣使用OU (Organization Unit),可以用來表示公司內部機構,如部門等,也可以用來表示設備、人員等。同時OU還可以有子OU,用來表示更為細致的分類。
LDAP中每一條記錄都有一個唯一的區別於其它記錄的名字DN(Distinguished Name),其處在“葉子”位置的部分稱作RDN;如dn:cn=tom,ou=animals,dc=domain,dc=com中tom即為 RDN;RDN在一個OU中必須是唯一的。 LDAP數據是“樹”狀的,這棵樹是可以無限延伸的.
LDAP 其實就是一個數據庫,但是跟我們平常的關系數據庫有所不同。關系數據庫是有一張一張的二維表格來存放數據的。ldap類似於dns系統,是樹狀的。用節點來存放數據。當然一個樹枝可以有n個節點,每個節點上存放的數據,都是以key => value的形式。就像dns系統。 .是根,下面是com,org,net,cn等等一些樹枝,這些樹枝下面還有abc.com, bcd.com等等樹枝。在每個樹枝下面都可以放節點,其實就是域名下面的主機:www,ftp,mail等等。所有的這些內容,組成了一個dns樹,在 ldap里面叫數據庫。
存儲LDAP配置信息及目錄內容的標准文本文件格式是LDIF(LDAP Interchange Format),使用文本文件來格式來存儲這些信息是為了方便讀取和修改,這也是其它大多數服務配置文件所采取的格式。LDIF文件常用來向目錄導入或更改記錄信息,這些信息需要按照LDAP中schema的格式進行組織,並會接受schema 的檢查,如果不符合其要求的格式將會出現報錯信息。
在LDAP中目錄是按照樹型結構組織,目錄由條目(Entry)組成,條目相當於關系數據庫中表的記錄;條目是具有區別名DN(Distinguished Name)的屬性(Attribute)集合,DN相當於關系數據庫表中的關鍵字(Primary Key);屬性由類型(Type)和多個值(Values)組成,相當於關系數據庫中的域(Field)由域名和數據類型組成, 只是為了方便檢索的需要,LDAP中的Type可以有多個Value,而不是關系數據庫中為降低數據的冗余性要求實現的各個域必須是不相關的。LDAP中條目的組織一般按照地理位置和組織關系進行組織,非常的直觀。LDAP把數據存放在文件中,為提高效率可以使用基於索引的文件數據庫,而不是關系數據庫。LDAP協議集還規定了DN的命名方法、存取控制方法、搜索格式、復制方法、URL格式、開發接口等。LDAP對於這樣存儲這樣的信息最為有用,也就是數據需要從不同的地點讀取,但是不需要經常更新。常見的屬性(Attribute)有:
二:在java中使用LDAP用於身份驗證
要想在一個應用程序進入之前使用LDAP進行身份驗證,在登錄時后台接收要登錄的用戶名和密碼,首先新建用於驗證的類LDAPAuthentication
package com.hxkj.qrcode.action; import java.util.Hashtable; import javax.naming.AuthenticationException; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.Control; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; public class LDAPAuthentication { private final String URL = "ldap://127.0.0.1:389/"; private final String BASEDN = "ou=People,dc=example,dc=com"; private final String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory"; private LdapContext ctx = null; private final Control[] connCtls = null; private void LDAP_connect() { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY); env.put(Context.PROVIDER_URL, URL + BASEDN); env.put(Context.SECURITY_AUTHENTICATION, "simple"); String root = "cn=Directory Manager";// root env.put(Context.SECURITY_PRINCIPAL, root); env.put(Context.SECURITY_CREDENTIALS, "Admin123"); // 此處若不指定用戶名和密碼,則自動轉換為匿名登錄 try { ctx = new InitialLdapContext(env, connCtls); } catch (javax.naming.AuthenticationException e) { System.out.println("驗證失敗:" + e.toString()); } catch (Exception e) { e.printStackTrace(); } } private String getUserDN(String uid) { String userDN = ""; LDAP_connect(); try { SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); NamingEnumeration<SearchResult> en = ctx.search("", "uid=" + uid, constraints); if (en == null || !en.hasMoreElements()) { System.out.println("未找到該用戶"); } // maybe more than one element while (en != null && en.hasMoreElements()) { Object obj = en.nextElement(); if (obj instanceof SearchResult) { SearchResult si = (SearchResult) obj; userDN += si.getName(); userDN += "," + BASEDN; } else { System.out.println(obj); } } } catch (Exception e) { System.out.println("查找用戶時產生異常。"); e.printStackTrace(); } return userDN; } public boolean authenricate(String UID, String password) { boolean valide = false; String userDN = getUserDN(UID); try { ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN); ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password); ctx.reconnect(connCtls); System.out.println(userDN + " 驗證通過"); valide = true; } catch (AuthenticationException e) { System.out.println(userDN + " 驗證失敗"); System.out.println(e.toString()); valide = false; } catch (NamingException e) { System.out.println(userDN + " 驗證失敗"); valide = false; } return valide; } }
在登錄的action中,獲取用戶名(uid)、密碼(password)
LDAPAuthentication _this = new LDAPAuthentication();
if(_this.authenricate(uid, password)){
//進入主程序
//主程序相關操作
}
如果驗證通過,進入主程序。(驗證時要開啟LDAP服務,可以使用OpenDJ)。

安裝完成后,打開bat目錄下的control-panel.bat進入OpenDJ控制面板,登陸后可以看到openDJ相關的基本信息和運行狀態,可進行相關操作。
點擊控制面板的“管理條目”,便可以打開創建時的基dn的管理界面。