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

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

評論