• 将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项目连接数据库操作

    下一篇:

  • 相关阅读:
    (01)Docker简介
    Gym-101242B:Branch Assignment(最短路,四边形不等式优化DP)
    2019牛客暑期多校训练营(第三场)G: Removing Stones(启发式分治)
    POJ
    高维前缀和
    HDU
    BZOJ
    HDU
    POJ
    Gym-100648B: Hie with the Pie(状态DP)
  • 原文地址:https://www.cnblogs.com/xiongzaiqiren/p/13134737.html
Copyright © 2020-2023  润新知