Java6.0 API for LDAP概述
從JDK5.0開始,對LDAP協議的數據訪問操作就被集成在javax的擴展API包中,並隨同JDK一併發佈,這一章節,我們主要介紹API包中的類信息。
javax.naming.directory 包的結構
常用API解析
javax.naming.directory.InitialDirContext,初始化目錄服務上下文類
該類是LDAP數據內容的操作工具類,通過該類可以執行綁定LDAP服務器、新增LDAP條目、獲取條目實例、修改條目屬性、刪除條目和根據條件搜索條目等操作。常用方法說明如下:
初始化LDAP 目錄服務上下文(相當於使用JDBC打開一個數據庫鏈接)
InitialDirContext(Hashtable<?,?> environment)
綁定/創建LDAP條目對象(相當於新增一個LDAP條目數據bind(Name
name, Object obj, Attributes attrs)
bind(String name, Object obj, Attributes attrs)
createSubcontext(Name name, Attributes attrs)
createSubcontext(String name, Attributes attrs)
獲取條目實例(屬性集)
getAttributes(Name name)
getAttributes(Name name, String[] attrIds)
getAttributes(String name)
getAttributes(String name, String[] attrIds)
修改條目屬性
modifyAttributes(Name name, int mod_op, Attributes attrs)
modifyAttributes(Name name, ModificationItem[] mods)
modifyAttributes(String name, int mod_op, Attributes attrs)
modifyAttributes(String name, ModificationItem[] mods)
u
刪除條目
destroySubcontext(Name name)
destroySubcontext(String name)
根據屬性集搜索條目
search(Name name, Attributes matchingAttributes)
search(Name name, Attributes matchingAttributes, String[] attributesToReturn)
search(String name, Attributes matchingAttributes)
search(String name, Attributes matchingAttributes, String[] attributesToReturn)
u
根據過濾器搜索條目
search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons)
search(Name name, String filter, SearchControls cons)
search(String name, String filterExpr, Object[] filterArgs, SearchControls cons)
search(String name, String filter, SearchControls cons)
javax.naming.directory.BasicAttribute,LDAP基本屬性對象
該類用來表示LDAP條目中的單個屬性對象。在目錄服務中,每個屬性名稱是可以對應多個的屬性值的。
構建屬性對象
BasicAttribute(String id)
BasicAttribute(String id, boolean ordered)
BasicAttribute(String id, Object value)
BasicAttribute(String id, Object value, boolean ordered)
添加屬性值
add(int ix, Object attrVal),添加屬性值到多值屬性的指定位置
add(Object attrVal) , 追加屬性值到多值屬性尾部
判斷屬性值是否包含
contains(Object attrVal) , 多值屬性中有一個值是匹配的,返回true
獲取屬性值
get(),取得屬性值中的一個
get(int ix),從多值屬性中的指定位置取值
獲取屬性ID
getID(),屬性的ID就是屬性名
刪除屬性值
remove(int ix),刪除指定位置的屬性值
remove(Object attrval),刪除指定的屬性值
javax.naming.directory.BasicAttributes,LDAP實體的屬性集
該類表示一個LDAP條目綁定的屬性集合,在絕大多數情況下,一個LDAP條目存在多個屬性。
構造屬性集
BasicAttributes()
BasicAttributes(boolean ignoreCase),屬性ID是否大小寫敏感,建議不要使用敏感
BasicAttributes(String attrID, Object val)
BasicAttributes(String attrID, Object val, boolean ignoreCase)
獲取屬性集中的單個屬性對象
get(String attrID)
獲取全部屬性的枚舉
getAll()
獲取全部屬性的ID枚舉
getIDs()
u
添加新屬性
put(Attribute attr)
put(String attrID, Object val)
u
移除指定屬性
remove(String attrID)
javax.naming.directory.SearchControls , LDAP目錄服務搜索控制對象
該類負責控制LDAP搜索行爲的範圍、設定返回結果數上限,搜索耗時上限,指定結果所包括的屬性集等。
設定搜索行爲的範圍
setSearchScope(int scope)
u
設定返回結果數上限
setCountLimit(long limit)
u
設定搜索耗時上限
setTimeLimit(int ms) , 以毫秒爲單位
u
指定結果所包括的屬性集
setReturningAttributes(String[] attrs)
javax.naming.directory.SearchResult , 表示.search() 方法的返回結果集中的一項。
SearchResult類是對LDAP條目屬性集的封裝。在search()操作中可能返回完整的條目屬性,也可能是條目屬性的一部分。
獲取SearchResult封裝的條目屬性
getAttributes()
以上只列舉了LDAP操作API的常用部分,更多更詳細的描述,請參考 Sun Java6.0 API DOC。
LDAP操作代碼樣例
在這個章節中,我們將結合LDAP操作的代碼實例瞭解API使用。
初始化LDAP 目錄服務上下文
該例子中,我們使用uid=linly,ou=People,dc=jsoso,dc=net這個賬號,鏈接位於本機8389端口的LDAP服務器(ldap://localhost:8389),認證方式採用simple類型,即用戶名/密碼方式。
private static void initialContext() throws NamingException{
if(singleton == null){
singleton = new LDAPConnection();
/*
* 在實際編碼中,這些環境變量應儘可能通過配置文件讀取
*/
//LDAP服務地址
singleton.sLDAP_URL = "ldap://localhost:8389";
//管理員賬號
singleton.sMANAGER_DN = "uid=linly,ou=People,dc=jsoso,dc=net";
//管理員密碼
singleton.sMANAGER_PASSWORD = "coffee";
//認證類型
singleton.sAUTH_TYPE = "simple";
//JNDI Context工廠類
singleton.sCONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
singleton.envProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, singleton.sCONTEXT_FACTORY);
singleton.envProps.setProperty(Context.PROVIDER_URL, singleton.sLDAP_URL);
singleton.envProps.setProperty(Context.SECURITY_AUTHENTICATION, singleton.sAUTH_TYPE);
singleton.envProps.setProperty(Context.SECURITY_PRINCIPAL, singleton.sMANAGER_DN);
singleton.envProps.setProperty(Context.SECURITY_CREDENTIALS, singleton.sMANAGER_PASSWORD);
/*
* 綁定ldap服務器
*/
singleton.dirCtx = new InitialDirContext(singleton.envProps);
}
}
通過一個Hashtable或者Properties對象爲LDAP的Context設置參數,而後初始化InitialDirContext,即可綁定LDAP服務。這相當於JDBC中獲取數據庫的Connection對象。
綁定/創建LDAP條目對象
用戶可以使用bind方法創建新的LDAP條目,下面的代碼創建一個DN:"ou=Employee , dc=jsoso ,dc=net"的OrganizationUnit類LDAP條目如下:
public boolean createOrganizationUnit(){
String ldapGroupDN = "ou=Employee , dc=jsoso ,dc=net";
try {
/*
* 查找是否已經存在指定的OU條目
* 如果存在,則打印OU條目的屬性信息
* 如果不存在,則程序會拋出NamingException異常,進入異常處理
*/
Attributes attrs = dirContext.getAttributes(ldapGroupDN);
System.out.println("Find the group , attributes list :");
NamingEnumeration<String> nEnum = attrs.getIDs();
for( ; nEnum.hasMore() ; ){
String attrID = nEnum.next();
Attribute attr = (Attribute)attrs.get(attrID);
System.out.println(attr.toString());
}
return false;
} catch (NamingException e) {
/*
* 沒有找到對應的Group條目,新增Group條目
*/
//創建objectclass屬性
Attribute objclass = new BasicAttribute("objectclass");
objclass.add("top");
objclass.add("organizationalunit");
//創建cn屬性
Attribute cn = new BasicAttribute("ou", "Employee");
//創建Attributes,並添加objectclass和cn屬性
Attributes attrs = new BasicAttributes();
attrs.put(objclass);
attrs.put(cn);
//將屬性綁定到新的條目上,創建該條目
try {
dirContext.bind(ldapGroupDN, null, attrs);
System.out.println("Group created successful");
return true;
} catch (NamingException e1) {
e1.printStackTrace();
}
}
return false;
}
或者使用createSubcontext方法創建亦可,以下例子我們新增一個inetorgperson類的LDAP條目:
/**
* 創建LDAP用戶條目
* @param user
* @return
*/
public boolean createUser(LDAPUser user){
if(user == null){
return false;
}
if(user.getUserID() == null || user.getUserID().length() == 0
|| user.getFirstName() == null || user.getFirstName().length() == 0
|| user.getLastName() == null || user.getLastName().length() == 0
|| user.getCommomName() == null || user.getCommomName().length() == 0){
return false;
}
//判斷用戶條目是否已經存在
if(isUserexist(user.getDistinguishedName())){
return true;
}
/*
* 新建條目屬性集
*/
Attributes attrs = new BasicAttributes();
setBasicAttribute(attrs , "objectclass" , "top,person,organizationalPerson,inetorgperson");
setBasicAttribute(attrs , "cn" , user.getCommomName());
setBasicAttribute(attrs , "givenname" , user.getFirstName());
setBasicAttribute(attrs , "sn" , user.getLastName());
setBasicAttribute(attrs , "uid" , user.getUserID());
setBasicAttribute(attrs , "userpassword" , user.getPassword());
//添加用戶條目節點
try {
dirContext.createSubcontext(user.getDistinguishedName(), attrs);
System.out.println("Add User(" + user.getDistinguishedName() + ") ok.");
return true;
} catch (NamingException e) {
e.printStackTrace();
}
return false;
}
獲取條目屬性
下面一段代碼獲取entryDN參數指定條目中的屬性集合,並打印到控制檯
/**
* 獲取一個指定的LDAP Entry
* @param entryDN
*/
public void find(String entryDN){
try {
Attributes attrs = dirContext.getAttributes(entryDN);
if (attrs != null) {
NamingEnumeration<String> nEnum = attrs.getIDs();
for( ; nEnum.hasMore() ; ){
String attrID = nEnum.next();
Attribute attr = (Attribute)attrs.get(attrID);
System.out.println(attr.toString());
}
System.out.println();
}else{
System.out.println("No found binding.");
}
}catch(NamingException ne) {
ne.printStackTrace();
}
}
修改條目屬性
修改DN=user.getDistinguishedName()的條目中的cn、givenname、sn和userpassword四個屬性值。
(注:參數DirContext.REPLACE_ATTRIBUTE有另外兩個常量:DirContext.ADD_ATTRIBUTE;DirContext.REMOVE_ATTRIBUTE,分別表示新增屬性和刪除屬性。)
/**
* 修改用戶信息
* @param user
* @return
* @throws Exception
*/
public boolean modifyUser(LDAPUser user) throws Exception {
//用戶對象爲空
if (user == null) {
throw new Exception("No user information!n");
}
//檢查uid
String userDN = user.getDistinguishedName();
if (userDN == null && userDN.length() == 0) {
throw new NamingException("No userDN you specify!n");
}
//判斷用戶條目是否已經存在
if(!isUserexist(userDN)){
return false;
}
//設置屬性
Attributes attrs = new BasicAttributes();
setBasicAttribute(attrs, "cn", user.getCommomName());
setBasicAttribute(attrs, "givenname", user.getFirstName());
setBasicAttribute(attrs, "sn", user.getLastName());
setBasicAttribute(attrs, "userpassword", user.getPassword());
//修改屬性
try{
dirContext.modifyAttributes(user.getDistinguishedName(),DirContext.REPLACE_ATTRIBUTE, attrs);
System.out.println("User(" + user.getDistinguishedName() + ") information modified.n");
return true;
}catch(NamingException ne){
ne.printStackTrace();
}
return false;
}
刪除條目
刪除DN= userDN條目
/**
* 刪除用戶
* @param userDN
* @return
*/
public boolean deleteUser(String userDN) {
if(!isUserexist(userDN)) {
return true;
}
try {
dirContext.destroySubcontext(userDN);
System.out.println("User( " + userDN + ") deleted.n");
return true;
} catch (NamingException e) {
e.printStackTrace();
}
return false;
}
根據屬性集搜索條目
根據屬性集matchingAttributes中的匹配值,在上下文DN= "ou=People,dc=jsoso ,dc=net"中搜索它的所有子樹中的匹配條目。
(注:SearchControls的SCOPE參數詳見SearchControls SCOPE補充說明)
/**
* 通過屬性搜索LDAP範例
* @return
*/
public void searchByAttribute(Attributes matchingAttributes){
String baseDN = "ou=People,dc=jsoso ,dc=net";
SearchControls cons = new SearchControls();
cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
try {
Name baseName = new LdapName(baseDN);
NamingEnumeration<SearchResult> ne = dirContext.search(baseName, matchingAttributes);
SearchResult entry = null;
for(;ne.hasMore();){
entry = ne.next();
showEntry(entry);
}
} catch (NamingException e) {
e.printStackTrace();
}
}
根據過濾器搜索條目
根據過濾器條件,在上下文DN = "ou=People,dc=jsoso ,dc=net"中,搜索它的所有子樹中的匹配條目。
(注:過濾器filter的相關語法詳見LDAP filter語法補充說明)
/**
* 通過過濾器搜索LDAP範例
* @return
*/
public void searchByFilter(String filter){
String baseDN = "ou=People,dc=jsoso ,dc=net";
SearchControls cons = new SearchControls();
cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
try {
NamingEnumeration<SearchResult> ne = dirContext.search(baseDN, filter , cons);
SearchResult entry = null;
for(;ne.hasMore();){
entry = ne.next();
showEntry(entry);
}
} catch (NamingException e) {
e.printStackTrace();
}
}
相關補充
javax.naming.Name對象說明
在API中,我們常常見到對LDAP上下文條目有兩種參數形式,一種是大家都熟悉的String參數,如: String baseDN = "ou=People,dc=jsoso ,dc=net";
另一種是使用javax.naming.Name類型的參數,那麼Name類和String有什麼區別呢?
簡單的說,Name是對String類DN的封裝,它把一個完整的DN字竄分解成了RDN的list。這個list的順序剛好和String相反。就拿"ou=People,dc=jsoso ,dc=net"爲例,Name中的RDN順序是[0]=net,[1]=jsoso,[2]=People。這樣做的好處是更方便對Name進行操作,比如取其前綴或者後綴。
SearchControls SCOPE補充說明
LDAP filter語法補充說明
filter的運算符
filter布爾運算符
搜索過濾器示例
下列過濾器將搜索包含一個或多個 manager 屬性值的條目。這也稱爲存在搜索: manager=*
下列過濾器將搜索包含通用名 Ray Kultgen 的條目。這也稱爲等價搜索:cn=Ray Kultgen
下列過濾器返回所有不包含通用名 Ray Kultgen 的條目:(!(cn=Ray Kultgen))
下列過濾器返回的所有條目中都有包含子字符串 X.500 的說明屬性:description=*X.500*
下列過濾器返回所有組織單元爲 Marketing 且說明字段中不包含子字符串 X.500 的條目: (&(ou=Marketing)(!(description=*X.500*)))
下列過濾器返回所有組織單元爲 Marketing 且 manager 爲 Julie Fulmer 或 Cindy Zwaska 的條目: (&(ou=Marketing)(|(manager=cn=Julie Fulmer,ou=Marketing,dc=siroe,dc=com)(manager=cn=Cindy Zwaska,ou=Marketing,dc=siroe,dc=com)))
下列過濾器返回所有不代表人員的條目: (!(objectClass=person))
下列過濾器返回所有不代表人員且通用名近似於 printer3b 的條目:(&(!(objectClass=person))(cn~=printer3b))