?
??? LDAP的英文全稱是Lightweight Directory Access Protocol,即輕量級(jí)目錄訪問(wèn)協(xié)議.我們
知道,人們對(duì)計(jì)算機(jī)網(wǎng)絡(luò)的使用和管理涉及了各種龐雜的資源,信息.為了提高性能,便于使
用,有效管理分布式應(yīng)用的服務(wù),資源,用戶及別的對(duì)象信息,這些信息需要清晰,一致地組
織起來(lái).基于這樣的需求,描述各種用戶,應(yīng)用,文件,打印機(jī)和其它可從網(wǎng)絡(luò)訪問(wèn)的資源的
信息被集中到一個(gè)特殊的數(shù)據(jù)庫(kù)中,這種數(shù)據(jù)庫(kù)被稱為目錄.目錄存放對(duì)象的公開(kāi)或非公開(kāi)的
信息,這些信息以某種順序組織,描述了每個(gè)對(duì)象的細(xì)節(jié).電話簿,圖書(shū)館藏書(shū)卡片目錄就是
常見(jiàn)的目錄.
???? LDAP是基于X.500標(biāo)準(zhǔn)的,訪問(wèn) X.500 目錄需要某種協(xié)議,例如:目錄訪問(wèn)協(xié)議 (DAP).
然而,DAP 需要大量的系統(tǒng)資源和支持機(jī)制來(lái)處理復(fù)雜的協(xié)議.LDAP 僅通過(guò)使用原始 X.500
目錄存取協(xié)議 (DAP) 的功能子集而減少了所需的系統(tǒng)資源消耗,而且可以根據(jù)需要定制.此
外,與X.500不同,LDAP支持TCP/IP,這對(duì)訪問(wèn)Internet是必須的.
??? 為了能對(duì)LDAP協(xié)議進(jìn)行更好的理解,我們需要對(duì)以下概念有初步的認(rèn)識(shí):
目錄:Directory,存放對(duì)象的信息,這些信息以某種順序組織,詳細(xì)描述每個(gè)對(duì)象.
目錄信息樹(shù):DIT,Directory Information Tree,目錄條目的集合構(gòu)成了目錄信息樹(shù).
條目:Entry,目錄信息樹(shù)中的一個(gè)結(jié)點(diǎn),是一個(gè)對(duì)象信息的集合,是目錄信息中最基本的
單位,包含該對(duì)象的一系列屬性.
屬性:Attribute,屬性描述對(duì)象的特征.一個(gè)屬性由屬性類型(type)和一個(gè)或多個(gè)屬性值
(values)構(gòu)成.
相對(duì)標(biāo)識(shí)名:RDN,Relative Distinguished Name,條目的名字.
唯一標(biāo)識(shí)名:DN,Distinguished Name,在一個(gè)目錄信息樹(shù)中唯一標(biāo)識(shí)一個(gè)條目的名字.
??? LDAP(輕量級(jí)目錄訪問(wèn)協(xié)議,Lightweight Directory Access Protocol)是實(shí)現(xiàn)提供被稱為目錄服務(wù)的信息服務(wù)。
目錄服務(wù)是一種特殊的數(shù)據(jù)庫(kù)系統(tǒng),其專門(mén)針對(duì)讀取,瀏覽和搜索操作進(jìn)行了特定的優(yōu)化。目錄一般用來(lái)包含描
述性的,基于屬性的信息并支持精細(xì)復(fù)雜的過(guò)濾能力。目錄一般不支持通用數(shù)據(jù)庫(kù)針對(duì)大量更新操作操作需要的
復(fù)雜的事務(wù)管理或回卷策略。而目錄服務(wù)的更新則一般都非常簡(jiǎn)單。這種目錄可以存儲(chǔ)包括個(gè)人信息、web鏈結(jié)、
jpeg圖像等各種信息。為了訪問(wèn)存儲(chǔ)在目錄中的信息,就需要使用運(yùn)行在TCP/IP之上的訪問(wèn)協(xié)議—LDAP。
??? LDAP目錄中的信息是是按照樹(shù)型結(jié)構(gòu)組織,具體信息存儲(chǔ)在條目(entry)的數(shù)據(jù)結(jié)構(gòu)中。條目相當(dāng)于關(guān)系數(shù)據(jù)庫(kù)中
表的記錄;條目是具有區(qū)別名DN(Distinguished Name)的屬性(Attribute),DN是用來(lái)引用條目的,DN相當(dāng)于
關(guān)系數(shù)據(jù)庫(kù)表中的關(guān)鍵字(Primary Key)。屬性由類型(Type)和一個(gè)或多個(gè)值(Values)組成,相當(dāng)于關(guān)系數(shù)
據(jù)庫(kù)中的字段(Field)由字段名和數(shù)據(jù)類型組成,只是為了方便檢索的需要,LDAP中的Type可以有多個(gè)Value,
而不是關(guān)系數(shù)據(jù)庫(kù)中為降低數(shù)據(jù)的冗余性要求實(shí)現(xiàn)的各個(gè)域必須是不相關(guān)的。LDAP中條目的組織一般按照地理位置
和組織關(guān)系進(jìn)行組織,非常的直觀。LDAP把數(shù)據(jù)存放在文件中,為提高效率可以使用基于索引的文件數(shù)據(jù)庫(kù),而不
是關(guān)系數(shù)據(jù)庫(kù)。類型的一個(gè)例子就是mail,其值將是一個(gè)電子郵件地址。
WebLogic的內(nèi)置的LDAP Server支持IETF LDAP為L(zhǎng)DAPv3制定的控制訪問(wèn)模型。下面這個(gè)片斷將講述在內(nèi)置的LDAP
Server中怎樣實(shí)現(xiàn)控制訪問(wèn)。可以通過(guò)編輯訪問(wèn)控制文件來(lái)將這些規(guī)則直接應(yīng)用到目錄的入口。
WebLogic中的訪問(wèn)控制文件是acls.prop。在Server的lib中可以找到這個(gè)文件。
這個(gè)文件的所有訪問(wèn)控制規(guī)則都被注釋掉了,如果想更改這些規(guī)則,你要手工更改這個(gè)文件。
注意:WebLogic Server內(nèi)置的LDAP Server在默認(rèn)的情況下只允許Admin帳號(hào)訪問(wèn),WebLogic Server的security providers
只使用Admin帳號(hào)訪問(wèn)內(nèi)置的LDAP Server。如果你不想使用外部的LDAP Brower訪問(wèn)WebLogic Server的內(nèi)置的LDAP Server,
或者你只想使用Admin帳號(hào)訪問(wèn)內(nèi)置的LDAP Server,你不需要編輯acls.prop文件,
訪問(wèn)控制文件(The Access Control File)
訪問(wèn)控制文件(acls.prop)包含內(nèi)置的LDAP Server的整個(gè)目錄的完整的訪問(wèn)控制列表(ACL)。
這個(gè)文件中的每一行都包含一個(gè)訪問(wèn)控制規(guī)則。一個(gè)訪問(wèn)控制規(guī)則由下面接個(gè)部分組成:
??? 訪問(wèn)控制位置(Access Control Location)
?????? 每個(gè)訪問(wèn)控制規(guī)則都應(yīng)用于LDAP目錄中的一個(gè)給定的位置。這個(gè)位置通常是一個(gè)區(qū)別命名(DN),但有一個(gè)例外,這就是[root],如果訪問(wèn)控制規(guī)則應(yīng)用到整個(gè)目錄,則只需要指定位置為[root]就可以了!
?????? 如果被訪問(wèn)或更改的入口的位置與訪問(wèn)控制規(guī)則指定的位置不相等,或在訪問(wèn)控制規(guī)則指定的位置的下級(jí),則這個(gè)訪問(wèn)控制規(guī)則將不會(huì)被執(zhí)行。
?? 訪問(wèn)控制范圍(Access Control Scope)
?????? 訪問(wèn)控制范圍有2種:
?????? Entry-一個(gè)Entry范圍的訪問(wèn)控制列表只在下面的情況下被執(zhí)行:
?????? LDAP目錄的入口的DN與訪問(wèn)控制規(guī)則指定的位置相同。這樣的規(guī)則對(duì)于包含了比并行和副入口更敏感信息的單獨(dú)入口非常有用。
?????? Subtree-意味著訪問(wèn)控制規(guī)則指定的位置及子樹(shù)都可以適用這條規(guī)則。
??????? 如果Entry與Subtree在訪問(wèn)控制規(guī)則中有沖突,則Entry要優(yōu)先于Subtree。
?? 訪問(wèn)權(quán)限(Access Rights)
??????? 訪問(wèn)權(quán)限應(yīng)用于整個(gè)對(duì)象或?qū)ο蟮膶傩裕?個(gè)值:grant(準(zhǔn)許)或deny(拒絕)。訪問(wèn)權(quán)限指定了LDAP操作的類型。
??
?? 許可(grant或deny)
?? 應(yīng)用規(guī)則的屬性(attribute)
?? 允許或拒絕訪問(wèn)的主題(subject)
?? 在weblogic可以編寫(xiě)程序來(lái)訪問(wèn)LDAP.上手時(shí)可以選擇JXplorer工具。
?? 1.LDAP Server及LDAP Browser:
????? 對(duì)于WLS LDAP為理解起來(lái)簡(jiǎn)單,去掉限制的方法是修改bea\weblogic81\server\lib\acls.prop文件后。修改方法:
在該文件最后添加以下幾行。
[root]|entry#grant:s,r,o,w,c,m#[all]#public
[root]|subtree#grant:s,r,o,w,c,m#[all]#public:
[root]|subtree#grant:a,d,e,i,n,b,t#[entry]#public:
cn=schema|entry#grant:s,r,o,w,c,m#[all]#public:
cn=schema|entry#grant:a,d,e,i,n,b,t#[entry]#public:
注意,該文件中這些行之間,以及其他行之間不能有空行,否則啟動(dòng)WLS會(huì)報(bào)錯(cuò)的。修改好之后就可以啟動(dòng)WLS了,
啟動(dòng)后進(jìn)入Console里修改Ldap Server的密碼。密碼修改完后需要再重新啟動(dòng)一次WLS。
LDAP剛上手的時(shí)候沒(méi)有方便的工具會(huì)很費(fèi)勁。我看了CSDN上“兔八哥”的文章,用JXplorer,感覺(jué)很不錯(cuò)。
想看這篇文章,到CSDN上搜一下“兔八哥”,系列中No.12就是關(guān)于JXplorer的配置和使用。我的連接參數(shù)如下:
Host:localhost//根據(jù)實(shí)際修改
Port:7001
Protocol:LDAP v3
Base DN:dc=ldapdomain//根據(jù)實(shí)際修改
Level:User+Password
User DN:cn=Admin
Password:weblogic//根據(jù)實(shí)際修改
.編程操作LDAP Server。
?下面四個(gè)JAVA方法,分別用于初始化,查詢,添加,刪除,修改,關(guān)閉連接。
?記得每次都需要先大概連接,操作,然后關(guān)閉連接。和使用數(shù)據(jù)庫(kù)差不多。
?
?????? 首先是需要用到的頭文件:
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls ;
import javax.naming.NamingEnumeration;
import javax.naming.directory.SearchResult;
import javax.naming.directory.Attributes ;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.ModificationItem;
import java.lang.reflect.Method;
import java.io.BufferedReader;
import java.io.InputStreamReader;
然后是一個(gè)類域,用于保存上下文:
?
DirContext ctx = null;
?
然后是初始化:
?
??? public void init(){
??????? String account="Admin";//操作LDAP的帳戶。默認(rèn)就是Admin。
??????? String password="weblogic";//帳戶Admin的密碼。
??????? String root="dc=ldapdomain"; //所操作的WLS域。也就是LDAP的根節(jié)點(diǎn)的DC
??????? Hashtable env = new Hashtable();
??????? env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");//必須這樣寫(xiě),無(wú)論用什么LDAP服務(wù)器。
??????? env.put(Context.PROVIDER_URL, "ldap://localhost:7001/" + root);//LDAP服務(wù)器的地址:端口。對(duì)WLS端口就是7001
??????? env.put(Context.SECURITY_AUTHENTICATION, "none");//授權(quán)界別,可以有三種授權(quán)級(jí)別,但是如果設(shè)為另外兩種都無(wú)法登錄,我也不知道為啥,但是只能設(shè)成這個(gè)值"none"。
??????? env.put(Context.SECURITY_PRINCIPAL, "cn=" + account + "," + root);//載入登陸帳戶和登錄密碼
??????? env.put(Context.SECURITY_CREDENTIALS, password);
??????? try{
??????????? ctx = new InitialDirContext(env);//初始化上下文
??????????? System.out.println("認(rèn)證成功");//這里可以改成異常拋出。
??????? }catch(javax.naming.AuthenticationException e){
??????????? System.out.println("認(rèn)證失敗");
??????? }catch(Exception e){
??????????? System.out.println("認(rèn)證出錯(cuò):"+e);
??????? }
?}
查詢操作:
?
?public void search(){//我只能按照某些屬性查找節(jié)點(diǎn),偶還不會(huì)怎么查找一個(gè)目錄或按照更復(fù)雜的正則式查找特定節(jié)點(diǎn)/目錄
? try{
?? SearchControls constraints = new SearchControls();
?? constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
?? System.out.print("what would you want to search:");
?? BufferedReader bd=new BufferedReader(new InputStreamReader(System.in));
?? String s=bd.readLine();
?? NamingEnumeration en = ctx.search("", "uid="+s, constraints); //要查詢的UID。如果是*則可以查到所有UID的節(jié)點(diǎn)
?? if(en == null){
??? System.out.println("Have no NamingEnumeration.");
?? }
?? if(!en.hasMoreElements()){
??? System.out.println("Have no element.");
?? }
?? while (en != null && en.hasMoreElements()){//可以查出多個(gè)元素
?????? Object obj = en.nextElement();
?????? if(obj instanceof SearchResult){
?????????? SearchResult si = (SearchResult) obj;
?????????? System.out.println("\tname: " + si.getName());
?????????? Attributes attrs = si.getAttributes();
?????????? if (attrs == null){
?????????????? System.out.println("\tNo attributes");
?????????? }else{
?????????????? for (NamingEnumeration ae = attrs.getAll(); ae.hasMoreElements();){//獲得該節(jié)點(diǎn)的所有屬性
?????? Attribute attr = (Attribute) ae.next();//下一屬性
?????? String attrId = attr.getID();//獲得該屬性的屬性名
?????? for (Enumeration vals = attr.getAll();vals.hasMoreElements();){//獲得一個(gè)屬性中的所有屬性值
?????????? System.out.print("\t\t"+attrId + ": ");
?????????? Object o = vals.nextElement();//下一屬性值
?????????? if(o instanceof byte[])
?????????????? System.out.println(new String((byte[])o));
?????????? else
?????????????? System.out.println(o);
?????? }
?????????????? }
?????????? }
?????? }
?????? else{
?????????? System.out.println(obj);
?????? }
?????? System.out.println();
?? }
? }catch(Exception e){
?? System.out.println("Exception in search():"+e);
? }
??? }
?
添加操作:
?
??? public void add(){
???? try{
?? String newUserName = "stella";
?? BasicAttributes attrs = new BasicAttributes();
?? BasicAttribute objclassSet = new BasicAttribute("objectclass");
?? objclassSet.add("person");
?? objclassSet.add("top");
?? objclassSet.add("organizationalPerson");
?? objclassSet.add("inetOrgPerson");
?? objclassSet.add("wlsUser");
?? attrs.put(objclassSet);
?? attrs.put("sn", newUserName);
?? attrs.put("uid", newUserName);
?? attrs.put("cn", newUserName);
?? ctx.createSubcontext("uid=" + newUserName+",ou=people,ou=myrealm", attrs);? //添加一個(gè)節(jié)點(diǎn),我還不會(huì)添加目錄
? }catch(Exception e){
?? System.out.println("Exception in add():"+e);
? }
??? }
修改操作:
?
??? public void edit(){
???? try{
?? String account = "stella";//修改以前舊的值
?? String sn = "stella sn";//修改以后新的值
?? ModificationItem modificationItem[] = new ModificationItem[1];
?? modificationItem[0] =
??? new ModificationItem(
???? DirContext.REPLACE_ATTRIBUTE,
???? new BasicAttribute("sn", sn));//所修改的屬性
?? ctx.modifyAttributes("uid=" + account, modificationItem);??? //執(zhí)行修改操作
? }catch(Exception e){
?? System.out.println("Exception in edit():"+e);
? }
??? }
刪除節(jié)點(diǎn)操作:
?
??? public void delete(){
???? try{
?? String uid = "stella";
?? ctx.destroySubcontext("uid=" + uid);? //按照UID刪除某個(gè)節(jié)點(diǎn)。我還不會(huì)刪除一個(gè)目錄。
?? }catch(Exception e){
??? System.out.println("Exception in edit():"+e);
?? }
??? }
關(guān)閉連接:
?
??? public void close(){
??????? if(ctx != null)
??????? {
??????????? try
??????????? {
??????????????? ctx.close();
??????????? }
??????????? catch (NamingException e)
??????????? {
??????????????? System.out.println("NamingException in close():"+e);
??????????? }
??????? }???
??? }
我對(duì)LDAP的理解:它是用于對(duì)資源的管理和服務(wù)的訪問(wèn)協(xié)議,在Weblogic平臺(tái)上的JNDI(包含EJB和DataSource)都是提供它來(lái)提供的。
正是JNDI的服務(wù)和RMI結(jié)合就形成J2EE平臺(tái)上分布式的應(yīng)用,因此說(shuō)到底層,還是LDAP協(xié)議的支持。