將Ldap組織結構及用戶信息同步到MySQL,用Spring Boot項目操作


  從上一篇《將Mybatis引入Spring Boot項目連接數據庫操作》知道了如何在Spring Boot項目操作數據庫,學會了增刪查改基本操作方法。本節記錄如何從Ldap獲取組織結構及用戶信息並導入數據庫。

一,引入Maven依賴並設置ldap連接信息

  首先在pom.xml添加引入ldap依賴,如下所示:

<!-- LDAP -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>

  保存后等待自動加載插件,加載完成后在application.properties配置文件中寫目標ldap連接信息:

# 目標ldap地址
spring.ldap.urls=ldap://192.168.10.168:389
# base是Base DN 即根節點
spring.ldap.base=DC=ldap,DC=local
# 指定用戶的username是User DN即distinguishedName,可分辨名稱、標識名稱
spring.ldap.username=CN=Administrator,CN=Users,DC=ldap,DC=local
# 指定用戶的密碼
spring.ldap.password=這里寫密碼

  上面是示例。如果不確定信息是否正確,可以用LDAPSoft Ldap Browser,AdminLdap等客戶端工具連接測試。能正確加載組織結構及用戶信息代表連接信息正確。保存配置。

二,從ldap獲取數據的基礎方法,用戶及部門實體模型

  在項目中新建package包,為了容易區分取名“LdapDemo”,在里面新建3個Class類,分別取名LdapPerson,LdapDepartment,LdapService。前兩個是ldap用戶信息實體模型和ldap部門信息實體模型,第3個是寫獲取數據等基礎方法的Service。

  LdapPerson.java代碼如下:

package xxh.springbootmvc.xxhdemo1.LdapDemo;

public class LdapPerson {
    public String getObjectClass() {
        return objectClass;
    }

    public void setObjectClass(String objectClass) {
        this.objectClass = objectClass;
    }

    public String getCn() {
        return cn;
    }

    public void setCn(String cn) {
        this.cn = cn;
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    public String getsAMAccountName() {
        return sAMAccountName;
    }

    public void setsAMAccountName(String sAMAccountName) {
        this.sAMAccountName = sAMAccountName;
    }

    public String getSn() {
        return sn;
    }

    public void setSn(String sn) {
        this.sn = sn;
    }

    public String getGivenName() {
        return givenName;
    }

    public void setGivenName(String givenName) {
        this.givenName = givenName;
    }

    public String getObjectGUID() {
        return objectGUID;
    }

    public void setObjectGUID(String objectGUID) {
        this.objectGUID = objectGUID;
    }

    public boolean isDeleted() {
        return isDeleted;
    }

    public void setDeleted(boolean deleted) {
        isDeleted = deleted;
    }

    public boolean isPrivilegeHolder() {
        return isPrivilegeHolder;
    }

    public void setPrivilegeHolder(boolean privilegeHolder) {
        isPrivilegeHolder = privilegeHolder;
    }

    public boolean isRecycled() {
        return isRecycled;
    }

    public void setRecycled(boolean recycled) {
        isRecycled = recycled;
    }

    public String getDistinguishedName() {
        return distinguishedName;
    }

    public void setDistinguishedName(String distinguishedName) {
        this.distinguishedName = distinguishedName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    private String objectClass; // organizationalPerson
    private String cn; // 名稱、唯一標識
    private String displayName; // 顯示名
    private String sAMAccountName; // 登錄名(唯一標識)
    private String sn; //
    private String givenName; //
    private String objectGUID;

    private boolean isDeleted; // 刪除的、禁用的
    private boolean isPrivilegeHolder; // 特權
    private boolean isRecycled; // 恢復的
    private String distinguishedName; // DN
    private String description;
}

保存。

  LdapDepartment.java代碼如下:

package xxh.springbootmvc.xxhdemo1.LdapDemo;

public class LdapDepartment {
    public String getObjectClass() {
        return objectClass;
    }

    public void setObjectClass(String objectClass) {
        this.objectClass = objectClass;
    }

    public String getOu() {
        return ou;
    }

    public void setOu(String ou) {
        this.ou = ou;
    }

    public String getObjectGUID() {
        return objectGUID;
    }

    public void setObjectGUID(String objectGUID) {
        this.objectGUID = objectGUID;
    }

    public boolean isDeleted() {
        return isDeleted;
    }

    public void setDeleted(boolean deleted) {
        isDeleted = deleted;
    }

    public boolean isPrivilegeHolder() {
        return isPrivilegeHolder;
    }

    public void setPrivilegeHolder(boolean privilegeHolder) {
        isPrivilegeHolder = privilegeHolder;
    }

    public boolean isRecycled() {
        return isRecycled;
    }

    public void setRecycled(boolean recycled) {
        isRecycled = recycled;
    }

    public String getDistinguishedName() {
        return distinguishedName;
    }

    public void setDistinguishedName(String distinguishedName) {
        this.distinguishedName = distinguishedName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    private String objectClass; // organizationalUnit
    private String ou; //名稱、唯一標識
    private String objectGUID;

    private boolean isDeleted; // 刪除的、禁用的
    private boolean isPrivilegeHolder; // 特權
    private boolean isRecycled; // 恢復的
    private String distinguishedName; // DN
    private String description;
}

 

  LdapService.java代碼如下:

package xxh.springbootmvc.xxhdemo1.LdapDemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.stereotype.Service;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import java.io.*;
import java.util.List;

import static org.springframework.ldap.query.LdapQueryBuilder.query;

@Service
public class LdapService {
    @Autowired
    private LdapTemplate ldapTemplate;

    // 獲取Ldap部門
    public List<LdapDepartment> getLdapDepartment(String objectClass,String DN) {
        if (null == objectClass || objectClass.length() < 1)
            objectClass = "organizationalUnit";
        System.out.println("getLdapDepartment> " + objectClass + "," + DN);
        ldapTemplate.setIgnorePartialResultException(true);
        return ldapTemplate.search(
                query().where("objectclass").is(objectClass)
                        .and("distinguishedName").like(DN),
                new LdapDepartmentAttributesMapper());

    }
    // 自定義序列化Ldap部門實體
    private class LdapDepartmentAttributesMapper implements AttributesMapper<LdapDepartment> {
        @Override
        public LdapDepartment mapFromAttributes(Attributes attrs) throws NamingException {
            LdapDepartment ldapDepartment = new LdapDepartment();
            if (null != attrs.get("objectClass")) {
                ldapDepartment.setObjectClass((String) attrs.get("objectClass").get());
            }
            if (null != attrs.get("ou")) {
                ldapDepartment.setOu((String) attrs.get("ou").get());
            }
            if (null != attrs.get("objectGUID")) {
                // 將ldap的objectGUID轉換成字符串
                ldapDepartment.setObjectGUID(convertObjectGUID(attrs.get("objectGUID").get()));
            }

            if (null != attrs.get("isDeleted")) {
                ldapDepartment.setDeleted((boolean) attrs.get("isDeleted").get());
            }
            if (null != attrs.get("isPrivilegeHolder")) {
                ldapDepartment.setPrivilegeHolder((boolean) attrs.get("isPrivilegeHolder").get());
            }
            if (null != attrs.get("isRecycled")) {
                ldapDepartment.setRecycled((boolean) attrs.get("isRecycled").get());
            }

            if (null != attrs.get("distinguishedName")) {
                ldapDepartment.setDistinguishedName((String) attrs.get("distinguishedName").get());
            }
            if (null != attrs.get("description")) {
                ldapDepartment.setDescription((String) attrs.get("description").get());
            }

            return ldapDepartment;
        }
    }

    // 獲取Ldap用戶
    public List<LdapPerson> getLdapPerson(String objectClass,String DN) {
        if(null==objectClass || objectClass.length()<1)
            objectClass="organizationalPerson";

        ldapTemplate.setIgnorePartialResultException(true);
        return ldapTemplate.search(
                query().where("objectclass").is(objectClass)
                        .and("distinguishedName").is(DN),
                new LdapPersonAttributesMapper());
    }
    // 自定義序列化Ldap用戶實體
    private class LdapPersonAttributesMapper implements AttributesMapper<LdapPerson> {
        @Override
        public LdapPerson mapFromAttributes(Attributes attrs) throws NamingException {
            LdapPerson ldapPerson = new LdapPerson();
            if (null != attrs.get("objectClass")) {
                ldapPerson.setObjectClass((String) attrs.get("objectClass").get());
            }
            if (null != attrs.get("cn")) {
                ldapPerson.setCn((String) attrs.get("cn").get());
            }
            if (null != attrs.get("displayName")) {
                ldapPerson.setDisplayName((String) attrs.get("displayName").get());
            }
            if (null != attrs.get("sAMAccountName")) {
                ldapPerson.setsAMAccountName((String) attrs.get("sAMAccountName").get());
            }
            if (null != attrs.get("sn")) {
                ldapPerson.setSn((String) attrs.get("sn").get());
            }
            if (null != attrs.get("givenName")) {
                ldapPerson.setGivenName((String) attrs.get("givenName").get());
            }
            if (null != attrs.get("objectGUID")) {
                // 將ldap的objectGUID轉換成字符串
                ldapPerson.setObjectGUID(convertObjectGUID(attrs.get("objectGUID").get()));
            }

            if (null != attrs.get("isDeleted")) {
                ldapPerson.setDeleted((boolean) attrs.get("isDeleted").get());
            }
            if (null != attrs.get("isPrivilegeHolder")) {
                ldapPerson.setPrivilegeHolder((boolean) attrs.get("isPrivilegeHolder").get());
            }
            if (null != attrs.get("isRecycled")) {
                ldapPerson.setRecycled((boolean) attrs.get("isRecycled").get());
            }

            if (null != attrs.get("distinguishedName")) {
                ldapPerson.setDistinguishedName((String) attrs.get("distinguishedName").get());
            }
            if (null != attrs.get("description")) {
                ldapPerson.setDescription((String) attrs.get("description").get());
            }

            return ldapPerson;
        }
    }

    // 示例:獲取全部用戶名
    public List<String> getAllPersonNames() {
        ldapTemplate.setIgnorePartialResultException(true);
        return ldapTemplate.search(
                query().where("objectclass").is("person"), (AttributesMapper<String>) attrs -> (String) attrs.get("cn").get());
    }

    //region 這里都是解決ldap獲取數據中的objectGUID亂碼問題,雖然解決了亂碼但是值不一樣,該值不建議當做標識使用。
    /**
     * 對象轉數組
     * @param obj
     * @return
     */
    private static byte[] toByteArray (Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray ();
            oos.close();
            bos.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return bytes;
    }

    /**
     * 數組轉對象
     * @param bytes
     * @return
     */
    private static Object toObject (byte[] bytes) {
        Object obj = null;
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream (bytes);
            ObjectInputStream ois = new ObjectInputStream (bis);
            obj = ois.readObject();
            ois.close();
            bis.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        return obj;
    }

    private static String AddLeadingZero(int k) {
        return (k <= 0xF) ? "0" + Integer.toHexString(k) : Integer.toHexString(k);
    }
    private static String convertObjectGUID(Object ObjectGUID) {
        byte[] GUID = toByteArray(ObjectGUID);

        String strGUID = "";
        String byteGUID = "";

        //Convert the GUID into string using the byte format
        for (int c = 0; c < GUID.length; c++) {
            byteGUID = byteGUID + "\\" + AddLeadingZero((int) GUID[c] & 0xFF);
        }
//        strGUID = "{";
        strGUID = strGUID + AddLeadingZero((int) GUID[3] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[2] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[1] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[0] & 0xFF);
        strGUID = strGUID + "-";
        strGUID = strGUID + AddLeadingZero((int) GUID[5] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[4] & 0xFF);
        strGUID = strGUID + "-";
        strGUID = strGUID + AddLeadingZero((int) GUID[7] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[6] & 0xFF);
        strGUID = strGUID + "-";
        strGUID = strGUID + AddLeadingZero((int) GUID[8] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[9] & 0xFF);
        strGUID = strGUID + "-";
        strGUID = strGUID + AddLeadingZero((int) GUID[10] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[11] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[12] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[13] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[14] & 0xFF);
        strGUID = strGUID + AddLeadingZero((int) GUID[15] & 0xFF);
//        strGUID = strGUID + "}";

//        System.out.println("GUID (String format): " + strGUID);
//        System.out.println("GUID (Byte format): " + byteGUID);
        return strGUID;
    }
    //endregion

}

 

Service里面方法實現可以參考下面幾篇博客:

https://docs.spring.io/spring-ldap/docs/2.3.3.RELEASE/reference/#spring-ldap-basic-usage-search-lookup-attributesmapper

https://www.jianshu.com/p/77517e26a357

https://blog.csdn.net/a118170653/article/details/43449331

 

注意:

  1,LdapService類前面要加@Service標注。

  2,需要在類體聲明LdapTemplate才能在方法里使用(在方法里面聲明不行)。

@Autowired

private LdapTemplate ldapTemplate;

  3,查詢ldap組織結構及用戶信息需要使用拉姆達表達式,具體請看上面代碼示例。

 

三,調用LdapService獲取數據並以接口形式輸出顯示

  在項目里面創建Class類,命名為ldapTestController,在這里面寫接口調用LdapService獲取數據並以接口形式輸出顯示。如下:

 

package xxh.springbootmvc.xxhdemo1.LdapDemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableAutoConfiguration
@RequestMapping("/v1/ldapdemo")
public class ldapTestController {
    /* 聲明LdapService */
    @Autowired
    private LdapService ldapService;

    // http://localhost:8888/v1/ldapdemo/getPersonNameList
    /* 獲取所有用戶名稱接口 */
    @RequestMapping("/getPersonNameList")
    public Object queryPersonNameList() {
        return ldapService.getAllPersonNames();
    }

    // http://localhost:8888/v1/ldapdemo/getLdapDepartmentList?objectclass=&dn=
    // http://localhost:8888/v1/ldapdemo/getLdapDepartmentList?objectclass=&dn=
    // http://localhost:8888/v1/ldapdemo/getLdapDepartmentList?dn=OU=%E8%BF%90%E8%90%A5%E6%9C%8D%E5%8A%A1%E9%83%A8,DC=ldap,DC=local
    /* 根據篩選獲條件取部門接口 */
    @RequestMapping("/getLdapDepartmentList")
    public Object queryLdapDepartmentList(String objectclass, String dn) {
        if (null == dn || dn.length() < 1)
            dn = "OU=實施組,OU=運營服務部,DC=ldap,DC=local";

        return ldapService.getLdapDepartment(objectclass, dn);
    }

    // http://localhost:8888/v1/ldapdemo/getLdapPersonList?dn=OU=實施組,OU=運營服務部,DC=ldap,DC=local
    /* 根據篩選獲條件取用戶接口 */
    @RequestMapping("/getLdapPersonList")
    public Object queryLdapPersonList(String objectclass, String dn) {
        if (null == dn || dn.length() < 1)
            dn = "CN=劉備,OU=實施組,OU=運營服務部,DC=ldap,DC=local";

        return ldapService.getLdapPerson(objectclass, dn);
    }

}

我這里是直接用接口顯示出來。其實真實項目中是錄入到數據庫里面。

本篇博客涉及到的項目文件及目錄結構:

 

 

四,接口效果截圖

獲取所有用戶名稱接口  效果如下:

 

 

根據篩選獲條件取部門接口  效果如下:

 

 

 

 根據篩選獲條件取用戶接口  效果如下:

 

 

 

本篇總結就寫到這里了。

缺點:

  1,雖然將Ldap的objectGUID能轉換成字符串不再是亂碼,但是值不等於Ldap里面的objectGUID值。所以不建議用它作為數據對比的標識。

  2,本篇代碼還不能按照友好的上下級關系一層一層往下查找(目前是查出所有的部門或用戶,或者篩選已知部門或已知用戶)。

 

上一篇:將Mybatis引入Spring Boot項目連接數據庫操作

下一篇:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM