本文介紹LDAP目錄服務器的簡單概念以及如何使用Java操做LDAP做目錄服務器java
目錄是一個專門爲搜索和瀏覽而設計的數據庫,它也支持簡單的插入、刪除、修改功能。你能夠把它理解爲咱們傳統使用的關係型數據庫,可是他與咱們的關係型數據庫有着本質的區別,目錄的存儲結構相似於linux文件系統,他是一顆樹(相似下圖),因爲它是爲瀏覽和搜索而設計的,它的查詢速度很快,相反插入速度較慢,它也不支持事務和回滾以及複雜的插入、更新功能。目錄服務器可像關係型數據庫同樣對外提供數據服務,它能夠是單機或集羣式的。在集羣式的架構中每一個機器都擁有一致的數據備份。linux
樹中的每一個節點稱之爲條目(Entry),目錄服務是以條目爲基礎的,在上圖的樹型結構中,每一個條目都有一個惟一的絕對名字Directory Name(DN)和相對名字rDN。每一個條目具備一組屬性,每一個屬性有一個key,每一個key對應一個或多個value。具體每一個條目有哪些屬性由ObjectClass約束,也就是說每一個條目經過賦予ObjectClass來規定其必須擁有的屬性。git
例如上圖的babs條目中:數據庫
DN:uid=babs,ou=people,dc=example,dc=combash
相對於ou=people,dc=example,dc=com 節點的rDN:uid=babs服務器
ObjectClass:Person架構
LDAP全稱爲Lightweight Directory Access Protocol(輕量級目錄訪問協議),客戶端與目錄服務器遵循LDAP協議來發生交互,好比說新增一個節點,查詢某個節點的屬性等等。dom
與關係型數據庫同樣,LDAP目錄服務器是一個概念,包含許多具體實現的產品,好比關係型數據庫常見的有MySQL,Oracle等等。LDAP目錄服務器也有常見的具體實現,好比:OpenLDAP,Active Directory(Microsoft)。本文以OpenLDAP爲例介紹Java如何操做LDAP服務器。gitlab
看到目前爲止,你可能會以爲目錄服務器貌似和關係型數據庫服務器沒有什麼區別,到底何時該使用目錄服務器呢?ui
使用目錄服務器最多見的狀況就是多系統間的集中用戶管理,好比公司會使用OA,Confluence,gitlab,jira等等辦公系統。若是每一個系統都須要咱們記住一個帳號密碼,那無疑是很費力的。經過使用LDAP目錄服務器將多個應用的用戶集中管理起來,每一個應用都經過通用的LDAP協議與目錄服務器通訊,達到用戶信息集中管理的目的。事實上不少的開源項目都支持LDAP用戶認證(例如SuperSet,Hue等等)
package richstonedt.com;
import com.novell.ldap.*;
import com.novell.ldap.util.Base64;
import lombok.extern.slf4j.Slf4j;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* 參考地址:http://www.micmiu.com/opensource/java-ldap-demo/
*/
@Slf4j
public class App {
private static String ldapHost = "192.168.x.x";
private static int ldapPort = 389;
private static String ldapBindDN = "cn=Manager,dc=my-domain,dc=com";
private static String ldapPassword = "123456";
private static int ldapVersion = LDAPConnection.LDAP_V3;
/**
* 獲取鏈接
*
* @return A LDAP Connection
* @throws LDAPException
* @throws UnsupportedEncodingException
*/
@SuppressWarnings("deprecation")
private static LDAPConnection connection() throws UnsupportedEncodingException, LDAPException {
try {
LDAPConnection lc = new LDAPConnection();
//獲取鏈接
lc.connect(ldapHost, ldapPort);
//認證
lc.bind(ldapVersion, ldapBindDN, ldapPassword.getBytes("UTF8"));
log.info("鏈接LDAP服務器成功!");
return lc;
} catch (Exception e) {
log.debug("LDAP服務器鏈接失敗!");
throw e;
}
}
/**
* 搜索某目錄節點下全部節點及其屬性
* @param DN 目錄節點名
* @throws LDAPException
* @throws UnsupportedEncodingException
*/
public static void searchEntry(String DN) throws LDAPException, UnsupportedEncodingException {
LDAPConnection conn = connection();
try {
LDAPSearchResults searchResults = conn.search(DN,
LDAPConnection.SCOPE_SUB, "objectClass=*", null, false);
while (searchResults.hasMore()) {
LDAPEntry nextEntry;
try {
nextEntry = searchResults.next();
} catch (LDAPException e) {
log.debug("Error: " + e);
if (e.getResultCode() == LDAPException.LDAP_TIMEOUT
|| e.getResultCode() == LDAPException.CONNECT_ERROR) {
break;
} else {
continue;
}
}
log.info("DN :" + nextEntry.getDN());
log.info("|---- Attributes list: ");
LDAPAttributeSet attributeSet = nextEntry.getAttributeSet();
Iterator<LDAPAttribute> allAttributes = attributeSet.iterator();
while (allAttributes.hasNext()) {
LDAPAttribute attribute = allAttributes.next();
String attributeName = attribute.getName();
Enumeration<String> allValues = attribute.getStringValues();
if (null == allValues) {
continue;
}
while (allValues.hasMoreElements()) {
String value = allValues.nextElement();
if (!Base64.isLDIFSafe(value)) {
// base64 encode and then print out
value = Base64.encode(value.getBytes());
}
log.info("|---- ---- " + attributeName
+ " = " + value);
}
}
}
} finally {
if (conn.isConnected()) {
conn.disconnect();
}
}
}
/**
* 新增一個目錄節點
* @param baseDN
* @param rDN
* @param attribute
* @throws UnsupportedEncodingException
* @throws LDAPException
*/
public static void addEntry(String baseDN, String rDN, Map<String, String> attribute) throws UnsupportedEncodingException, LDAPException {
LDAPConnection conn = connection();
try {
LDAPAttributeSet attributeSet = new LDAPAttributeSet();
for (Map.Entry<String, String> entry : attribute.entrySet()) {
attributeSet.add(new LDAPAttribute(entry.getKey(), entry.getValue()));
}
String DN = rDN + "," + baseDN;
conn.add(new LDAPEntry(DN, attributeSet));
} finally {
if (conn.isConnected())
conn.disconnect();
}
}
/**
* 刪除一個目錄節點
* @param DN 目錄節點名
* @throws UnsupportedEncodingException
* @throws LDAPException
*/
public static void deleteEntry(String DN) throws UnsupportedEncodingException, LDAPException {
LDAPConnection conn = connection();
try {
conn.delete(DN);
} finally {
if (conn.isConnected()) {
conn.disconnect();
}
}
}
public static void main(String[] args) throws UnsupportedEncodingException, LDAPException {
//新增節點
Map<String, String> map = new HashMap<>();
map.put("objectclass", "inetOrgPerson");
map.put("cn", "liuruojing");
map.put("sn", "liuruojing");
addEntry("ou=userAccount,dc=my-domain,dc=com", "uid=liuruojing", map);
//查詢節點
searchEntry("uid=liuruojing,ou=userAccount,dc=my-domain,dc=com");
//刪除節點
deleteEntry("uid=liuruojing,ou=userAccount,dc=my-domain,dc=com");
}
}
複製代碼
注意:須要引入JLDAP的Maven依賴
<dependency>
<groupId>com.novell.ldap</groupId>
<artifactId>jldap</artifactId>
<version>4.3</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
複製代碼