什么是JNDI
在一個企業(yè)中,命名服務為讀者的應用程序在網絡上定位對象提供了一種方法。一個命名服務將對象和名稱聯(lián)系在了一起,并且可以通過它們指定的名稱找到相應的對象。
JNDI是Java命名和目錄接口,是一個為Java應用程序提供命名服務的應用程序編程接口(API)。它為開發(fā)人員提供了查找和訪問各種命名和目錄服務的通用、統(tǒng)一的接口,類似于JDBC都是構建在抽象層上。要使用JNDI,必須要安裝jdk 1.3以上版本。
JNDI包含了大量的命名和目錄服務,它使用通用接口來訪問不同種類的服務,可以同時連接到多個命名或目錄服務上并建立起邏輯關聯(lián)。
命名服務
命 名服務是一種服務,它提供了為給定的數據集創(chuàng)建一個標準名字的能力。它允許把名稱同Java對象或資源關聯(lián)起來,而不必指出對象或資源的物理ID。這類似 于字典結構(或者是Java的map結構),該結構中鍵映射到值。例如在Internet上的域名服務(domain naming service,DNS)就是提供將域名映射到IP地址的命名服務,在打開網站時一般都是在瀏覽器中輸入名字,通過DNS找到相應的IP地址,然后打開。
所有的因特網通信都使用TCP、UDP或IP協(xié)議。IP地址由4個字節(jié)32位二進制數字組成,數字和名字相比,對于人來說名字比數字要容易記憶,但對于計算機來講,它更善于處理數字。
其實所有的命名服務都提供DNS這種基本功能,即一個系統(tǒng)向命名服務注冊,命名服務提供一個值到另一個值的映射。然后,另外一個系統(tǒng)訪問命名服務就可以取得映射信息。這種交互關系對分布式企業(yè)級應用來講顯得非常重要。
在Java中,基本的名字操作包含在Context接口中。
目錄服務
目 錄服務是一種特殊類型的數據庫,與SQL Server、Access、Oracle等關系數據庫管理系統(tǒng)相反,構造目錄服務的目的是為了處理基于行為的事務,并且使用一種關系信息模型。目錄服務 將命名服務的概念進一步引申為提供具有層次結構的信息庫,這一信息庫除了包含一對一的關系外,還有信息的層次結構。對目錄服務而言,這種層次結構通常用于 優(yōu)化搜索操作,并且也可以按實際情況進行分布或者跨網絡復制。
一個目錄服務通常擁有一個名字服務(但是一個名字服務不必具有一個目錄服務)。如電話簿就是一個典型的目錄服務,一般先在電話簿里找到相關的人名,再找到這個人的電話號碼。
每一種目錄服務都可以存儲有關用戶名、用戶密碼、用戶組(如有關訪問控制的??? 信息)、以太網地址、IP地址等信息。它所支持的信息和操作會因為所使用的目錄服務的不同而不同。遺憾的是,訪問不同目錄服務的協(xié)議也會不同,所以讀者需要了解多???? 種API。
這就是JNDI的起源,就像JDBC一樣,JNDI充當不同名稱和目錄服務的通用API或者說是前端,然后使用不同的后端適配器來連接實際服務。如圖6-1顯示了JNDI和LDAP如何共同合作,為客戶提供一種完美的解決方案。
在這里,使用JNDI完成與LDAP服務器之間的通信,對開發(fā)者來說他們只擔心一個特殊協(xié)議(LDAP)和一個API(JNDI),而由開發(fā)商給他們自己的各個協(xié)議提供LDAP接口。事實上對這些流行的目錄服務中來說,都有產品可讓開發(fā)者通過LDAP與這些目錄服務通信。
JNDI 是J2EE技術中的一個完整的組件。它支持通過一個單一的方法訪問不同的、新的和已經存在的服務的方法。這種支持允許任何服務提供商執(zhí)行通過標準服務提供 商接口(SPI)協(xié)定插入JNDI框架。另外,JNDI允許Weblogic服務器上的Java應用程序通過插入適當的服務提供者來訪問像LDAP這樣的 標準化方式的外部目錄服務。
基本的目錄服務操作包含在DirContext接口中。
LDAP的介紹
輕量目錄訪問協(xié)議(lightweight directory access protocol,LDAP)是在20世紀90年代早期作為標準目錄協(xié)議進行開發(fā)的。它是目前最流行的目錄協(xié)議,與廠商跟平臺無關。
LDAP可以追溯到X.500協(xié)議,而X.500協(xié)議最初是基于OSI網絡協(xié)議發(fā)展起來的。LDAP的第3版協(xié)議是在RFC2251中定義的,并且已經非常成熟,它的最新補充部分包含LDAP的XML規(guī)范,稱為目錄服務標記語言。
Java語言通過使用LDAP API,如Netscape Directory 服務器可以直接使用LDAP,或者通過JNDI來使用LDAP。JNDI是J2SE中的標準API,是通用的API,不必綁定到LDAP。
LDAP 定義客戶應當如何訪問服務器中的數據,它并不指定數據應當如何存儲在服務器上。大多數情況下,開發(fā)者只需要和一個專為LDAP設計的目錄服務,或現有目錄 服務的LDAP前端打交道。LDAP能夠成為任何數據存儲類型的前端。目前最流行的目錄服務有NIS、NDS、Active Directory等都有某種類型的LDAP前端。
LDAP 和關系數據庫是兩種不同層次的概念,后者是存儲方式(同一層次如網格數據庫,對象數據庫),前者是存儲模式和訪問協(xié)議。LDAP是一個比關系數據庫抽象層 次更高的存儲概念,與關系數據庫的查詢語言SQL屬于同一級別。LDAP最基本的形式是一個連接數據庫的標準方式,該數據庫為讀查詢作了優(yōu)化。因此它可以 很快地得到查詢結果,不過在其他方面,例如更新操作等就慢得多。
從 另一個意義上來講,LDAP是實現了指定的數據結構的存儲,它是一種特殊的數據庫。但是LDAP和一般的數據庫不同,明白這一點是很重要的。LDAP對查 詢進行了優(yōu)化,與寫性能相比,LDAP的讀性能要優(yōu)秀很多。LDAP服務器也是用來處理查詢和更新LDAP目錄的。換句話說,LDAP目錄也是一種類型的 數據庫,但不是關系型數據庫。要特別注意的是,LDAP通常作為一個hierarchal數據庫使用,而不是一個關系數據庫。
1.LDAP數據
在LDAP中,數據被組織成一棵樹的形式,叫做目錄信息樹(directory information tree,DIT)。DIT中的第一個“葉子”叫做一個條目(entry),第一個條目叫根條目(root entry)。
一 個條目是由一個區(qū)分名稱DN(distinguished name)和任意一個屬性/值對組成。DN是一個條目的名字,它必須是唯一的,它類似于一個關系型數據庫的唯一關鍵字。DN也表明了該條目與DIT樹的其 他部分之間的關系,它類似于這種方式:一個文件的全路徑名表明硬盤上的一個特定文件與系統(tǒng)中的其他文件之間的關系。當從根目錄讀取文件時,讀取系統(tǒng)上的文 件路徑是從左到右讀取的,但是當從根目錄讀取DN時,是從右到左讀DN的。如:
uid = jordan,ou = nba,o = american
表示定義了在組織american中的小組為 nba的用戶jordan的用戶。其中一個DN名的最左邊部分叫相對區(qū)分名稱RDN(relative distinguished name),它由一個條目內的屬性/值組成,如前面的uid = jordan是RDN,后面的可有可無。
LDAP通常使用簡寫形式的助記符表示其名稱,常用的LDAP屬性及其定義如表6-1所示。
LDAP屬性及其定義
LDAP屬性 |
定義 |
o |
Organization:組織 |
ou |
Organization unit:組織單元 |
|
|
續(xù)表
LDAP屬性 |
定義 |
uid |
Userid:用戶id |
cn |
Common name:常見名稱 |
sn |
姓 |
givenname |
首名 |
dn |
Distinguished Name:區(qū)分名稱 |
|
E-mail Address:電子郵件地址 |
|
|
其中一個屬性可以有一個或多個值,如一個用戶可以有多個mail。
LDAP
X.500 ,一個 CCITT 的目錄服務器標準,是 OSI 否為套件的一部分。 X.500 標準定義了客戶端應用程序訪問 X.500 目錄的協(xié)議,叫做目錄訪問協(xié)議( DAP )。它在開放系統(tǒng)互連( OSI )協(xié)議棧的頂層。
因特網委員會認為需要 X.500 類型的訪問但底層的網絡基礎架構(是 TCP/IP 而不是 OSI )不同,基于 X.500 DAP 協(xié)議設計了一個新協(xié)議,叫做輕量級 DAP 或 LDAP 。 RFC 2251 定義了成為版本 3 的 LDAP ( LDAPv3 ),這是它的前身 LDAP v2 ( RFC 1777 )的改進。
LDAP 協(xié)議的目的是容易實現,特別是創(chuàng)建小的簡單的客戶端。一種嘗試簡化的成果是大量使用字符串來減少結構的使用。例如 DN ,在協(xié)議中以字符串表示,屬性類型名和大多數屬性值也是如此。
這個協(xié)議包含客戶端向服務器發(fā)送的請求,對于服務器的應答,不需要按照請求的順序進行。每一個請求有一個 ID ,所以請求和應答可以匹配。這個協(xié)議可以工作在 TCP 或 UDP 中,最常用的是 TCP 。
因為焦點在客戶端, LDAP 組織同時定義了 DN 的字符串表達( RFC 2553 ),搜索過濾器( RFC 1960 ),屬性語法( RFC 1778 ),為 C 語言提供的 API ( RFC 1823 ),訪問 LDAP 訪問的 URL 格式( RFC 1959 )。
LDAP v3 支持國際化,多種認證技術, referral ,以及一般的部署技術。使用 extensions 和 controls 添加新特性時不需要修改協(xié)議。
LDAP v3
國際化
國際化是通過國際化字符集( ISO 10646 )表示協(xié)議中的字符串元素(例如 DN )。 v3 與 v2 不同, v2 使用 UTF-8 編碼字符串。
認證
除了匿名,簡單(明文密碼)認證, LDAPv3 使用簡單認證以及安全層( SASL )認證架構( RFC 2222 )允許在 LDAP 中使用不同的認證技術。 SASL 定義了客戶端和服務器之間數據交換的認證的挑戰(zhàn) - 應答協(xié)議。
現在定義了一些 SASL 技術: DIGEST-MD5, CRAM-MD5 ,匿名,擴展, S/Key, GSSAPI 以及 Kerberos v4 。 LDAP v3 客戶端可以使用任意一種 SASL 技術,提供給支持這種技術的 LDAP v3 服務器。而且,新的(還沒有定義的) SASL 技術可以在不改變 LDAP 的情況下使用。
referrals
referral 是服務器發(fā)送個客戶端的信息,表示請求的信息可以在其他地方發(fā)現(很可能是其他服務器)。在 LDAP v2 中,服務器由服務器處理 referral ,不返回到客戶端。因為實現 referral 是非常負載的并且可能導致很復雜的客戶端。當服務器構建以及部署后, referral 就變得十分有用,但不是很多服務器支持服務端的 referral 處理。所以,使用一種方法修改協(xié)議允許返回 referral 。通過在將 referral 放置在“ partial result ”錯誤應答的錯誤信息中實現。
LDAP v3 顯式支持 referrals ,允許服務器直接向客戶端返回 referrals 。 referrals 不再本課中介紹,您可以求助于 JNDI 教程關于符合在應用程序中控制 referrals 的信息。
部署
LDAP 這種普通協(xié)議可以用來確保目錄客戶端和服務器“說同一種語言”。當不同的目錄客戶端和服務器部署在網絡中時,這些實體都說同樣的對象是非常有用的。
目錄架構描述,在其他東西中間,對象的類型,目錄可能有的對象的類型,對象的每個必須的或可選屬性。 LDAP v3 定義架構( RFC 2252 和 RFC 2256 )基于 X.500 標準為了在網絡中查找基本對象定義,例如,國家,地區(qū),組織,用戶 / 人,用戶組和設備。它定義了客戶端訪問服務器架構的方法,所以可以發(fā)現對象的類型以及服務器支持的屬性。
LDAPv3 進一步定義了表示屬性值的一組語法( RFC 2252 )。要編寫訪問架構信息的 Java 應用程序,請參考 JNDI 教程。
擴展
除了預定義的所有操作,例如“ search ”和“ modify ”之外, LDAPv3 定義了“ extended ”操作?!? extended ”將請求當作參數并且返回應答。請求中包含標識請求的標識符和請求參數。應答中包含請求執(zhí)行的結果?!? extended ”操作中的請求和應答叫做擴展。例如,可以為開始 TLS 定義擴展,它是客戶端向服務器的請求,用來開始 Start TLS 協(xié)議。
擴展可以是標準的( LDAP 委員會定義的)或者私有的(由供應商定義)。要編寫使用擴展的程序請參考 JNDI 教程。
Controls
添加新特性的另一種方法是使用 control 。 LDAP v3 允許通過使用 control 修改所有操作的行為。一個操作中可以發(fā)送任意多個 control ,同時結果中也可以返回任意數量的 control 。例如,您可以和“ search ”操作一起發(fā)送排序 control ,告訴服務器根據“ name ”屬性對結果進行。
和擴展一樣, control 可以是標準的也可以是私有的。標準 control 由平臺提供。編寫使用 control 的應用程序請參考 JNDI 教程。
將 JNDI 作為 LDAP 的 API
JNDI 和 LDAP 的模型在命名對象時都使用層次結構的名字空間。名字空間中的每一個對象都可能有屬性,而且這些屬性可以用來搜索對象。在這種層次上,兩個模型是類似的,所以 JNDI 可以對 LDAP 進行很好的映射也沒有什么稀奇的。
模型
您可以將 LDAP 的條目想象成 JNDI 的 DirContext 。每個 LDAP 條目包含名稱和一組屬性,以及可選的子條目集合。例如, LDAP 條目“ o=JNDITutorial ”可能有屬性“ objectclass ”和“ o ”,同時可能有子條目“ ou=Groups ”和“ ou=People ”。
在 JNDI 中, LDAP 條目“ o=JNDITutorial ”可以表示成名為“ o=JNDITutorial ”的上下文,它有兩個子上下文,名叫“ ou=Groups ”和“ ou=People ”。 LDAP 條目屬性使用 Attributes 接口表示,而獨立的屬性通過 Attribute 接口表示。
關于 LDAP 操作如何通過 JNDI 進行訪問的詳細信息請參考下一部分。
名字
為了聯(lián)合查詢,您提供給 JNDI 上下文方法的名稱可以跨越多個命名空間。這些叫做混合名字。當使用 JNDI 訪問 LDAP 服務時,您需要明白字符串中的斜杠(“ / ”)在 JNDI 中特殊的含義。如果 JNDI 條目包含這個字符,需要進行轉義(使用“ \ ”)。例如,使用名稱“ cn=O/R ”的 LDAP 條目在 JNDI context 的方法中,必須使用“ cn=O\\/R ”標識。關于名字的更多信息,請參考 JNDI 教程。 LdapName 和 Rdn 類簡要介紹了創(chuàng)建和操作 LDAP 名字的方法。
協(xié)議中 LDAP 的名稱總是完全的名字,表示從 LDAP 命名空間根開始的唯一條目(由服務器定義)。以下是一些 LDAP 全名的例子:
?
cn=John Smith, ou=Marketing, o=Some Corporation, c=gb cn=Vinnie Ryan, ou=People, o=JNDITutorial |
?
然而,在 JNDI 中,名字是相對的,即,您總是相對于上下文命名對象。例如,您可以相對于上下文“ ou=People, o=JNDITutorial ”對“ cn=Vinnie Ryan ”條目進行命名。或者,您可以相對于上下文“ o=JNDITutorial ”對條目“ cn=Vinnie Ryan, ou=People ”進行命名。或者,您可以創(chuàng)建初始上下文指向 LDAP 服務器命名空間的根,然后命名條目“ cn=Vinnie Ryan, ou=People, o=JNDITutorial ”。
在 JNDI 中,您同樣可以使用 LDAP 的 URL 來命名 LDAP 條目。請參考 JNDI 教程中的 LDAP URL 討論。
LDAP 操作如何映射到 JNDI API
LDAP 定義了一組操作或請求( RFC 2251 )。在 JNDI 中,這些操作被映射到 DirContext 和 LdapContext 接口中,它們都是 Context 的子接口。例如,當請求 DirContext 中的方法時。 LDAP 服務提供者通過將 LDAP 請求發(fā)送給 LDAP 服務器實現這個操作。
下表描述和 LDAP 操作對應的 JNDI 方法:
?
LDAP 操作 |
對應的 JNDI 方法 |
bind |
這是創(chuàng)建 LDAP 服務器初始連接的方式,對應 JNDI 中創(chuàng)建 InitialDirContext 對象。當應用程序創(chuàng)建初始上下文,它在環(huán)境參數中向服務器提供客戶端認證信息。要修改一個已經存在上下文的認證信息,使用 Context.addToEnvironment() 和 Context.removeFromEnvironment() 。 |
Unbind |
Context.close() 用來釋放上下文使用的資源。服務提供者的實現和 LDAP 的 unbind 操作有一些不同,資源在上下文之間共享,所以關閉上下文當資源被其他上下文使用時就不會釋放。如果您的意圖是釋放所有資源,需要關閉所有上下文。 |
Search |
JNDI 中對應方法是 DirContext.search() 中接收搜索過濾器( RFC 2254 )的重載形式。 |
modify |
JNDI 中對應方法是 DirContext.modifyAttributes() 中接收 DirContext.ModificationItems 數組的重載形式。示例請看修改屬性一節(jié)。 |
Add |
JNDI 中對應方法是 DirContext.bind() 和 DirContext.createSubcontext() 。您可以使用它們添加一個新的 LDAP 條目。使用 bind() ,您不但需要指定新條目的屬性集合同時需要和屬性一起的 Java 對象。示例請參考關聯(lián)屬性的添加、替換綁定一節(jié)。 |
Delete |
JNDI 中對應的方法是 Context.unbind() 和 Context.destroySubcontext() 。您可以使用它們移除 LDAP 條目。 |
modify DN/RDN |
JNDI 中對應方法是 Context.rename() 。請參考重命名對象一節(jié)得到詳細信息。 |
compare |
在 JNDI 中可以使用 DirContext.search() 代替。示例請參考 LDAP 比較操作一節(jié)。 |
abandon ? |
當您關閉上下文時,所有沒有應答的請求都被放棄。類似的,當關閉 NamingEnumeration ,相應的 LDAP “ search ”請求也放棄了。 |
Extended 操作 |
JNDI 中對應的方法是 LdapContext.extendedOperation() 。詳細信息請參考 JNDI 教程。 |
?
LDAP 錯誤碼如何映射到 JNDI 異常
LDAP 定義了一組狀態(tài)碼,它們是由 LDAP 服務器作為應答發(fā)送給客戶端的( RFC 2251 )。在 JNDI 中,錯誤條件由 Naming Exceptions 子類的檢查的異常標識。請參考 JNDI 異常類概述中的 Naming Exceptions 。
?
LDAP 狀態(tài)碼 |
含義 |
異?;虿僮? |
0 |
成功 |
報告成功 |
1 |
操作錯誤 |
NamingException |
2 |
協(xié)議錯誤 |
CommunicationException |
3 |
達到時間限制 |
TimeLimitExceededException |
4 |
達到大小限制 |
SizeLimitExceededException |
5 |
比較失敗 |
被 DirContext.search() 方法使用,不產生異常。 |
6 |
比較成功 |
被 DirContext.search() 方法使用,不產生異常。 |
7 |
認證方式不支持 |
AuthenticationNotSupportedException |
8 |
需要更強的認證 |
AuthenticationNotSupportedException |
9 |
只返回部分數據 |
如果環(huán)境參數“ java.naming.referral ”是“ ignore ”或錯誤的內容不包含 referral ,拋出 PartialResultException 。否則,使用內容創(chuàng)建一個 referral 。 |
10 |
發(fā)生 referral |
如果環(huán)境參數“ java.naming.referral ”是“ ignore ”,則忽略。如果參數是“ throw ”,拋出 ReferralException 。如果屬性是“ follow ”,由 LDAP 提供者處理 referral 。如果超過“ java.naming.ldap.referral.limit ”限制,拋出 LimitExceededException 。 |
11 |
達到管理限制 |
LimitExceededException |
12 |
不支持的關鍵擴展請求 |
OperationNotSupportedException |
13 |
需要機密信息 |
AuthenticationNotSupportedException |
14 |
SASL 綁定中 |
由 LDAP 提供者在認證過程中使用。 |
16 |
屬性不存在 |
NoSuchAttributeException |
17 |
未定義屬性類型 |
InvalidAttributeIdentifierException |
18 |
不合適的匹配 |
InvalidSearchFilterException |
19 |
常量違例 |
InvalidAttributeValueException |
20 |
屬性值正在使用中 |
AttributeInUseException |
21 |
屬性語法錯誤 |
InvalidAttributeValueException |
32 |
對象不存在 |
NameNotFoundException |
33 |
別名錯誤 |
NamingException |
34 |
DN 語法非法 |
InvalidNameException |
35 |
是葉子節(jié)點 |
LDAP 提供者使用,通常不產生異常。 |
36 |
別名解析錯誤 |
NamingException |
48 |
不合適的認證 |
AuthenticationNotSupportedException |
49 |
機密信息非法 |
AuthenticationException |
50 |
訪問權限不足 |
NoPermissionException |
51 |
忙 |
ServiceUnavailableException |
52 |
不可得 |
ServiceUnavailableException |
52 |
服務器不愿執(zhí)行 |
OperationNotSupportedException |
54 |
檢測到循環(huán) |
NamingException |
64 |
命名違例 |
InvalidNameException |
65 |
對象類型違例 |
padding: 0cm 5.4pt; border-left-color: #d4d0c8; width: 252.35pt; border-top-color: #d4d0c8;
發(fā)表評論
最新評論
|
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

評論