近期项目中有一个需求是需要整合LDAP开进行开发一个功能,该功能旨在同步LDAP服务器中的用户到本地数据库,然后在LDAP当中注册的账号都能在同一个平台中登录访问资源;那么首先就要知道LDAP为何物?LDAP既Lightweight Directory Access Protocol的英文缩写,轻量级目录访问协议。具体的概念介绍在这就不多做陈述,本文主要是记录介绍代码层面的功能开发跟实现;
package cn.ouryun.task;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import cn.ouryun.pojo.SysAccountModel;
import cn.ouryun.service.IUserService;
import lombok.extern.slf4j.Slf4j;
/**
* LDAP定时任务:定时同步数据到基础开发平台用户表中
* @author huangsiyuan
*
*/
@Slf4j
@Component
public class LDAPScheduledTask {
@Autowired
private IUserService userService;
/**
* 每天晚上0点更新数据
* @throws InterruptedException
*/
//@Scheduled(cron="0/3 * * * * *")
@Scheduled(cron = "0 0 0 * * ?")
public void updateLdapUsers() {
log.info("开始调度定时任务更新LDAP服务器账户");
Hashtable
env.put(Context.REFERRAL, "ignore");
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
//LDAP服务器url, 389是默认端口号
env.put(Context.PROVIDER_URL, "ldap://***.**.**.**:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
//账号: 用户名@域名为固定格式
env.put(Context.SECURITY_PRINCIPAL, "******@example.com");
//密码
env.put(Context.SECURITY_CREDENTIALS, "******");
try {
DirContext ctx = new InitialDirContext(env);// 初始化上下文
// 域节点
String searchBase = "dc=example, dc=com";
String searchFilter = "objectClass=User";
SearchControls searchCtls = new SearchControls(); // Create the
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); // Specify
// 根据设置的域节点、过滤器类和搜索控制器搜索LDAP得到结果
NamingEnumeration
//封装LDAP用户
List
SysAccountModel accountModel = null;
while (entries.hasMoreElements()) {
SearchResult sr = entries.nextElement();
//获取属性
Attributes attrs = sr.getAttributes();
//根据具体取值(用户名)
String disName = attrs.get("name")==null ? "null":attrs.get("name").toString();
//去除掉disName前缀name:
int index = disName.indexOf(":");
disName = disName.substring(index + 1, disName.length());
accountModel = new SysAccountModel();
accountModel.setAccName(disName);
accountList.add(accountModel);
}
if(accountList != null && accountList.size() > 0) {
userService.saveLdapAccount(accountList); //调用本地代码同步数据
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
这段代码是通过Spring定时任务每天晚上十二点去将LDAP服务器上的用户同步到我们平台的用户表中;而这里要说明的是,以下这段代码是用于校验账户的合法性
@SuppressWarnings("unused")
public Result userLdapLogin(String account, String password) throws Exception {
Hashtable
SysAccountModel accountModel = new SysAccountModel();
accountModel.setAccName(account);
env.put(Context.REFERRAL, "ignore");
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
//url
env.put(Context.PROVIDER_URL, "ldap://172.16.88.86:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
//账号
env.put(Context.SECURITY_PRINCIPAL, account + "@example.com");
//密码
env.put(Context.SECURITY_CREDENTIALS, password);
//初始化上下文(所谓初始化上下文就是通过InitialDirContext去校验LDAP的账户跟密码还有url连接是否正确,如果正确则返回dirContext对象,否则会抛出异常)
DirContext dirContext = new InitialDirContext(env);
DirContext dirContext = new InitialDirContext(env);如果账户名或者密码错误,则会抛出异常。在一些业务场景中,系统原有的登录机制
例如Shiro,如果整合了LDAP用户,则需要LDAP用户在LDAP上验证,就是让new InitialDirContext(env);去初始化账户密码,如果验证通过则放行让其访问系统资源;