Hyperf连接LDAP服务

PHP8.0连接LDAP

最近刚对接了下ldap服务,也是踩了一些坑,这里展示一下本地的开发过程以及部分代码

参考文档:
本地docker搭建ldap服务文档参考地址
PHP文档

准备:

  1. 启动一个开发环境的容器。 docker run -e TZ="Asia/Shanghai" -e LD_PRELOAD="/usr/lib/preloadable_libiconv.so php" --name base_openldap -v D:/WWW:/data -p 9605:9605 -it --privileged -u root --entrypoint /bin/sh hyperf/hyperf:8.0-alpine-v3.15-swoole-v4.8.7
  2. 检查容器内PHP的ldap扩展是否开启,直接命令行或者phpinfo搜索。php -module | grep ldap php -r "phpinfo();" | grep LDAP
  3. 如果没有ldap扩展,就安装扩展。用的镜像是alpine linux,alpine linux下apk的安装命令:apk search php-ldap //寻找合适的版本,apk add php8-ldap //安装,容器内默认php扩展目录 /usr/lib/php8/modules/,容器内默认php.ini配置文件所在位置 /etc/php8/
  4. 将修改后的容器重新打包为镜像(这一步看自己),docker commit -m="增加ldap扩展" -a="szh" 5419967f4cf8 hyperf_ldap //给装好扩展的容器生成一个镜像docker tag c236d50c41c5 username/hyperf_ldap:1.0 //给生成好的镜像打一个tag(tag最好前面拼接用户名)docker push username/hyperf_ldap:1.0 //试试推送到dockerhub
  5. 参考ldap服务文档搭建,下载docker-compose.yml,修改好自己的配置后,docker-compose up 启动服务
  6. 容器之间互相访问,需要在一个网络里面,两种加入网络方式:--net=openldap_default //启动容器时指定网络 docker network connect openldap_default 容器id //容器运行时,直接指定网络到openldap_default
  7. docker network ls, 查看刚刚启动的ldap网络。
  8. 运行刚打包好的镜像,并直接加入ldap服务的网络中,docker run -e TZ="Asia/Shanghai" -e LD_PRELOAD="/usr/lib/preloadable_libiconv.so php" --name demo_openldap -v D:/WWW:/data -p 9705:9705 -it --privileged -u root --entrypoint /bin/sh --net openldap_default user/hyperf_ldap:1.0

errorCode类是网上找了几个ldap_errno错误代码;开发时候多看一下PHP官方文档,一些方法高版本被修改或废弃了

<?php
/*
 * @author:
 * @name:ldap服务连接
 * @desc:
 * @LastEditTime:
 */
namespace App\Lib\Plugins\Ldap;

use Hyperf\Di\Annotation\Inject;

class Ldap
{

    public $ldapconn = false;

    /**
     * @Inject()
     * @var LdapCode
     */
    protected $errorCode;

    /**
     * name: ldap资源连接
     * Date: 2022/10/12 14:24
     * @param $ldapuri  // 例如: ldap://ldap.example.com:389
     * @param $username // 例如: cn=admin,dc=example,dc=org
     * @param $password // 例如: 123456
     */
    public function connect($ldapuri, $username, $password)
    {
        // 地址连接 注意这里并没有真正连接服务器,只是做了一个参数初始化和检测的操作
        $this->ldapconn = @ldap_connect($ldapuri); // 连接ldap
        if (FALSE === $this->ldapconn) {
            error(200, "ldap_connect 错误");
        }
        ldap_set_option($this->ldapconn,LDAP_OPT_PROTOCOL_VERSION,3);
        ldap_set_option($this->ldapconn, LDAP_OPT_REFERRALS, 0);
        // 进行登录用户验证 绑定到具有指定 RDN 和密码的 LDAP 目录 这里才是真正连接服务器
        if (TRUE !== ldap_bind($this->ldapconn, $username, $password)) {
            error(200, "ldap_bind 错误");
        }
    }

    /**
     * name: 添加条目、编辑条目
     * Date: 2022/10/12 15:36
     * @param $params //参数里面必须包含的验证字段 un_parent_dn(上级所在域)、un_cn(自己的cn)
     * @return bool
     */
    public function myldap_save($params)
    {
        $dn = $params['un_cn'].','.$params['un_parent_dn']; //即将添加或修改的节点
        unset($params['un_cn'], $params['un_parent_dn']);
        //在ldap某个组织中搜索是否已经存在相应数据
        $detail = $this->myldap_detail($dn);
        $entryInfo = $params;
        if($detail == false){
            //不存在就添加
            $bool = ldap_add($this->ldapconn, $dn, $entryInfo);
        }else{
            //存在就编辑
            //$bool = ldap_modify($this->ldapconn, $dn, $entryInfo);//ldap_modify不能对属性新增、删除
            $bool = ldap_mod_replace($this->ldapconn, $dn, $entryInfo);//ldap_mod_replace可以对属性新增、删除
        }
        return $bool;
    }

    /**
     * name: 判断条目是否存在,存在返回条目信息,不存在返回false
     * Date: 2022/10/12 14:30
     * @param $dn
     * @return array|false
     */
    public function myldap_detail($dn)
    {
        $filter = "(".explode(',', $dn)[0].")";
        //搜索ldap中是否已经存在相应数据
        $sr = @ldap_read($this->ldapconn, $dn, $filter);
        if(!$sr){
            error(200, $this->errorCode->codeMsg($this->ldapconn));
        }
        $entry = ldap_get_entries($this->ldapconn, $sr);
        return empty($entry['count'])? false: $entry;
    }

    /**
     * name: 删除条目
     * Date: 2022/10/12 15:12
     * @param $dn
     * @param $recursive //默认false,true为递归删除多个
     * @return bool TRUE on success, FALSE on failure
     */
    public function myldap_delete($dn, $recursive = false):bool
    {
        if($recursive == false){
            $result = @ldap_delete($this->ldapconn, $dn);
            if(!$result)    return false;
            return $result;
        }else{
            //搜索子节点
            $sr = @ldap_list($this->ldapconn, $dn,"ObjectClass=*",[""]);
            if(!$sr){
                error(200, $this->errorCode->codeMsg($this->ldapconn));
            }
            $info = ldap_get_entries($this->ldapconn, $sr);
            for($i=0; $i < $info['count']; $i++){
                //递归删除子节点
                $result = $this->myldap_delete($info[$i]['dn'], $recursive);
                if(!$result){
                    //如果删除失败,则返回结果
                    return($result);
                }
            }
            return $this->myldap_delete($dn);
        }
    }

    /**
     * dec: php8.0版本 ldap_connect返回的是一个资源,并非是实例对象
     */
    public function close()
    {
        //@ldap_unbind($this->ldapconn);
        @ldap_close($this->ldapconn);
    }

    /**
     * name: 用新值替换属性值
     * @param $dn
     * @param $entry ['uid'=>[] (删除掉mail属性(一些字段不允许删除)), 'mail'=>["9527@qq.com"] (添加或替换mail属性)]
     * @param $controls
     * @return bool
     */
    public function myldap_mod_replace($dn, $entry, $controls=null)
    {
        if($this->myldap_detail($dn) != false){
            $res = ldap_mod_replace($this->ldapconn, $dn, $entry, $controls);
            if(!$res){
                error(200, $this->errorCode->codeMsg($this->ldapconn));
            }
            return true;
        }
        return false;
    }

    /**
     * name: 修改密码
     * Date: 2022/10/12 17:51
     * @param $dn
     * @param $pwd //明文
     * @return bool
     */
    public function myldap_pwd($dn, $pwd)
    {
        $entry['userpassword'] = ["{MD5}".base64_encode(md5($pwd,true))];
        return $this->myldap_mod_replace($dn, $entry);
    }

    /**
     * name: 修改条目的名称(迁移)
     * @param $dn //老的dn。如  cn=mali,cn=admin,dc=example,dc=org
     * @param $newRdn //新的rdn。如  cn=newMali
     * @param $newParent //新的上级dn
     * @param $deleteOldRdn //老的dn 是否需要删除 true删除 false不删除
     * @return bool
     */
    public function myldap_rename($dn, $newRdn, $newParent, $deleteOldRdn=false)
    {
        if($this->myldap_detail($dn) != false && $this->myldap_detail($newRdn.','.$newParent) == false){
            return ldap_rename($this->ldapconn, $dn, $newRdn, $newParent, $deleteOldRdn);
        }
        return false;
    }
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值