LDAP入門http://www.reibang.com/p/7e4d99f6baaf
Spring LDAP呻待,是Spring的一個組件,實現(xiàn)對LDAP的操作奏篙。
在編程操作MySQL時迫淹,我們除了用JDBC,可能都會選用一些框架肺稀,比如JbdcTemplate应民。
JdbcTemplate的實現(xiàn)是通過傳入sql語句和RowMapper,query返回目標(biāo)列表稿静,或是傳入sql和參數(shù)改备,執(zhí)行update方法蔓倍。JdbcTemplate的優(yōu)點是簡化了與數(shù)據(jù)庫連接的代碼,以及避免了一些常見的錯誤默勾。
同樣的聚谁,Spring LDAP框架也提供了類似的特性——LdapTemplate。
優(yōu)點都是相通的环疼,Spring LdapTemplate的優(yōu)點是簡化了與LDAP交互的代碼朵耕。
按之前Spring配置JavaBean的方式,在xml文件配置LdapTemplate及其屬性值即可伪阶,本文將演示使用Springboot 用Java代碼的方式定義LdapTemplate处嫌,完成Spring ldap連接數(shù)據(jù)庫服務(wù)及進(jìn)行相關(guān)操作锰霜。
下面是使用Spring-ldap的依賴
<!-- spring ldapTemplate操作 -->
<dependency>
<groupId>com.sun</groupId>
<artifactId>ldapbp</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
先介紹一些Spring-ldap,因為網(wǎng)上有很多教程厨剪,在給出的工程依賴中有用spring-ldap的友存,也有spring-ldap-core的,而且還有版本問題直晨。筆者使用目前最新的spring-ldap-2.3.2.RELEASE。推薦直接使用罩句,這個最新版本敛摘。
spring-ldap框架,是Spring集成ldap操作的總和屯远,包含spring-ldap-core捕虽,spring-ldap-core-tiger泄私,spring-ldap-ldif-core,spring-ldap-odm等jar晌端,而通常我們在工程中只需要引入spring-ldap-core即可斩松,它提供了絕大部分功能。而且截至目前乳幸,spring-ldap的<version>2.3.2.RELEASE</version>不在maven的中央倉庫钧椰,不好獲取。但spring-ldap-core在瓶埋。
另外诊沪,Spring LDAP 2.0對jdk版本要求是1.6,并且開始支持ODM端姚,并后來引入Spring ldap pool連接池。
據(jù)本人嘗試巫湘,這些版本之間,變化差異很大尚氛。在新版本中可能有些關(guān)鍵的核心類阅嘶,都會被移動到不同的package下;一些老版本完成的愚鈍功能,可能在新版本中有了更好的實現(xiàn)或支持宪巨,所以在新版本中捏卓,一些“愚鈍”實現(xiàn)可能會被移除。
比如LdapTemplate遥金,原先在org.springframework.ldap包蒜田,在最新版本被移至core包。在spring-ldap-core的<version>2.0.2.RELEASE</version>版本中支持類似于JPA方式的LdapRepository美莫,但在2.3.2最新版本中梯捕,完全被移除傀顾,但是新版本增強(qiáng)的LdapTemplate,使得LdapTemplate功能更強(qiáng)大寒砖,可以完全替代LdapRepository嫉拐。
下面是用Java代碼的方式定義LdapTemplate,完成用Spring ldap連接LDAP服務(wù)器
import com.xxx.xxx.sim.ldap.constants.LdapConstans;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.pool.factory.PoolingContextSource;
import org.springframework.ldap.pool.validation.DefaultDirContextValidator;
import org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy;
import java.util.HashMap;
import java.util.Map;
/**
* LDAP 的自動配置類
*
* 完成連接 及LdapTemplate生成
*/
@Configuration
public class LdapConfiguration {
private LdapTemplate ldapTemplate;
@Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
Map<String, Object> config = new HashMap();
contextSource.setUrl(LdapConstans.url);
contextSource.setBase(LdapConstans.BASE_DC);
contextSource.setUserDn(LdapConstans.username);
contextSource.setPassword(LdapConstans.password);
// 解決 亂碼 的關(guān)鍵一句
config.put("java.naming.ldap.attributes.binary", "objectGUID");
contextSource.setPooled(true);
contextSource.setBaseEnvironmentProperties(config);
return contextSource;
}
@Bean
public LdapTemplate ldapTemplate() {
if (null == ldapTemplate)
ldapTemplate = new LdapTemplate(contextSource());
return ldapTemplate;
}
}
- 完成LdapTemplate的bean定義孝偎,是最關(guān)鍵的一步忱叭。因為后續(xù)的操作,對于LDAP目錄樹的CRUD操作侯谁,全都靠它完成章钾。
- 通過上面的代碼,在IOC容器完成bean的定義惨撇,我們在外部就可以注入使用LdapTemplate了府寒。
下面給出用LdapTemplate完成CRUD功能:
import com.xxx.xxx.sim.ldap.attribute.LdapDeptAttributeMapper;
import com.xxx.xxx.ldap.attribute.LdapUserAttributeMapper;
import com.xxx.xxx.xxx.ldap.module.dto.LdapUser;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import java.util.List;
public class ConfigTest extends BaseTest {
@Autowired
private LdapTemplate ldapTemplate;
/**
* 獲取所有 internal人員
* ou=Internal,ou=People
*/
@Test
public void listUsers(){
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "person"));
//查詢所有內(nèi)部人員
List<LdapUser> users = ldapTemplate.search("ou=internal,ou=People", filter.encode(), new LdapUserAttributeMapper());
for (LdapUser user: users ) {
System.out.println(user);
}
// Assert.assertEquals(123, users.size());
}
/**
* 根據(jù)userid 查找單個人員
*/
@Test
public void findUser(){
//uid=123,ou=internal,ou=People,o=xxx.com,o=xxx
DirContextAdapter obj = (DirContextAdapter) ldapTemplate.lookup("uid=123,ou=internal,ou=People");//BASE_DC 不用填
System.out.println(obj);
}
/**
* 根據(jù)部門編號o剖淀,查找部門
*/
@Test
public void findDept(){
//o=abcd,ou=Organizations,ou=People,o=xxx.com,o=xxx
DirContextAdapter obj = (DirContextAdapter) ldapTemplate.lookup("o=abcd,ou=Organizations");//BASE_DC 不用填
System.out.println(obj);
}
@Test
public void listDepts(){
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "organization"));
//search是根據(jù)過濾條件進(jìn)行查詢纵隔,第一個參數(shù)是父節(jié)點的dn炮姨,可以為空,不為空時查詢效率更高
List depts = ldapTemplate.search("", filter.encode(), new LdapDeptAttributeMapper());
System.out.println(depts.size());
// Assert.assertEquals(305600, depts.size());
}
}
- 在ldap中糊啡,有兩個"查詢"概念吁津,search和lookup。search是ldaptemplate對每一個entry進(jìn)行查詢碍脏,lookup是通過DN直接找到某個條目典尾。
- 在Ldap中,新增與刪除叫做綁定bind和解綁unBind河闰。這些方法LdapTemplate全部提供,并且還提供各種條件過濾等方法姜性,不如findAll(),list()等部念。
我們注意到,findAll(),list()肯定是返回一個java.util.List<T>妓湘,包括乌询,
//查詢所有internal人員
List<LdapUser> users = ldapTemplate.search("ou=internal,ou=People", filter.encode(), new LdapUserAttributeMapper());
也是返回列表楣责,列表里裝的是查詢出來的結(jié)果聂沙。但是上一篇文章用JNDI方式查詢出來的是
Attributes attrs = ctx.getAttributes("uid=123,ou=Internal,ou=People");//獲取到一個人員
Spring-ldap是基于JNDI實現(xiàn)的封裝,那是哪里實現(xiàn)的把Attributes轉(zhuǎn)成我們需要的Java Bean對象呢沮趣?
答案在new LdapUserAttributeMapper()坷随,這個接口實現(xiàn)了查詢結(jié)果到對象的轉(zhuǎn)化温眉。
import com.xxx.csb.sim.ldap.module.dto.LdapUser;
import org.springframework.ldap.core.AttributesMapper;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
/**
* 將ldap返回的結(jié)果,轉(zhuǎn)成指定對象
*/
public class LdapUserAttributeMapper implements AttributesMapper {
/**
* 將單個Attributes轉(zhuǎn)成單個對象
* @param attrs
* @return
* @throws NamingException
*/
public Object mapFromAttributes(Attributes attrs) throws NamingException {
LdapUser user = new LdapUser();
if(attrs.get("uid") != null){
user.setUsername( attrs.get("uid").get().toString());
}
if(attrs.get("cn") != null){
user.setUserCn( attrs.get("cn").get().toString());
}
if(attrs.get("mobile") != null){
user.setMobile( attrs.get("mobile").get().toString());
}
if(attrs.get("mail") != null){
user.setMail( attrs.get("mail").get().toString());
}
if(attrs.get("employeeNumber") != null){
user.setUserNumber( attrs.get("employeeNumber").get().toString());
}
if(attrs.get("type") != null){
user.setUserType( attrs.get("type").get().toString());
}
if(attrs.get("py") != null){
user.setPinyin(attrs.get("py").get().toString());
}
if(attrs.get("alias") != null){
user.setAlias(attrs.get("alias").get().toString());
}
if(attrs.get("departmentNumber") != null){
user.setDeptId(attrs.get("departmentNumber").get().toString());
}
if(attrs.get("departmentName") != null){
user.setDeptName(attrs.get("departmentName").get().toString());
}
if(attrs.get("jobname") != null){
user.setPositionName(attrs.get("jobname").get().toString());
}
if(attrs.get("modifyTimestamp") != null){
user.setModifyTimestamp(attrs.get("modifyTimestamp").get().toString());
}
return user;
}
}
可以看到轉(zhuǎn)化的過程非常繁瑣,無非就是拿JNDI查詢到的Attributes砂心,不停的獲取屬性值蛇耀,再設(shè)置到Java對象中;attrs.get("uid").get().toString()然后set译暂。
那好了,在每次查詢的時候褐桌,要查詢到多少列象迎,在這個AttributesMapper轉(zhuǎn)化方法中就要寫多少個砾淌,判斷及賦值。而且赃春,如果因為業(yè)務(wù)不同劫乱,要查詢不同的列,那AttributesMapper接口的實現(xiàn)必須重新寫狭吼。那有沒有支持復(fù)用的方式呢殖妇?答案是肯定的谦趣。下節(jié)分享spring ldap ODM , Object-Directory Mapping。
spring-ldap-2.3.2.RELEASE所有jar包下載
http://download.csdn.net/download/ljheee/10150501
Spring-ldap最新版官方文檔:
https://docs.spring.io/spring-ldap/docs/2.3.2.RELEASE/reference/