PHP如何将现有LDAP连接修改为LDAPS连接本地Windows Active Directory
报错原因
当前参数错误的直接诱因是ldap_connect入参格式不符合要求:
ldap_connect()仅接收LDAP服务器的URI作为输入,你将OU=ULTIMATE,DC=ultimate,DC=local这类基础DN拼接在服务器地址后,属于非法参数,直接导致连接句柄创建失败。
除此之外你的代码还存在两个AD适配问题,修正参数后也会触发绑定失败:
- Active Directory(AD)默认不使用
uid作为用户的RDN属性,你拼接的uid=xxx格式的绑定DN在AD中默认不存在。AD用户绑定可以直接使用用户名@域后缀的UPN格式(例如test@ultimate.local),无需手动拼接完整DN,兼容性更好。 - 若AD的LDAPS使用自签发证书,需要在运行PHP的服务器上将AD的根证书加入信任列表,否则会出现证书校验失败导致的连接错误,测试阶段可以临时关闭证书校验规避该问题。
权限问题解答
你的思路完全正确。如果普通域用户没有AD目录查询权限,推荐采用两次绑定的逻辑,符合最小权限安全规范:
- 先使用预设的、仅拥有AD只读查询权限的服务账号(不要直接用域管理员)完成首次LDAP绑定
- 用用户输入的账号名作为过滤条件,在AD中查询对应用户的完整DN
- 再使用查询得到的用户DN、用户输入的密码执行第二次LDAP绑定,绑定成功即代表用户身份验证通过
修正后的示例代码
普通绑定版本(用户自身有绑定权限时使用)
<?php session_start(); // 仅填LDAPS服务器URI,不要拼接DN $ldap_server = "ldaps://192.168.xxx.xxx:636"; // AD域后缀 $ldap_domain = "@ultimate.local"; $input_username = $_POST["username"]; $input_password = $_POST["password"]; $ldap_con = ldap_connect($ldap_server); ldap_set_option($ldap_con, LDAP_OPT_PROTOCOL_VERSION, 3); // 测试用临时关闭证书校验,生产环境配置证书信任后删除此行 ldap_set_option($ldap_con, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER); // 用UPN格式绑定,无需手动拼接DN $ldap_bind_user = $input_username . $ldap_domain; if(@ldap_bind($ldap_con, $ldap_bind_user, $input_password)) { $_SESSION['username'] = $input_username; header("Location: Startseite.php"); exit; } else { echo "Invalid Credential"; } ldap_unbind($ldap_con); ?>
服务账号预查询版本(普通用户无查询权限时使用)
<?php session_start(); $ldap_server = "ldaps://192.168.xxx.xxx:636"; $ldap_base_dn = "OU=ULTIMATE,DC=ultimate,DC=local"; // 预设拥有AD只读权限的服务账号 $service_account = "svc_ldap_query@ultimate.local"; $service_pass = "你的服务账号密码"; $input_username = $_POST["username"]; $input_password = $_POST["password"]; $ldap_con = ldap_connect($ldap_server); ldap_set_option($ldap_con, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($ldap_con, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER); // 第一步:服务账号绑定查询用户DN if(ldap_bind($ldap_con, $service_account, $service_pass)) { $filter = "(samaccountname=$input_username)"; $result = ldap_search($ldap_con, $ldap_base_dn, $filter, array("dn")); $entries = ldap_get_entries($ldap_con, $result); if($entries['count'] == 1) { $user_dn = $entries[0]['dn']; // 第二步:用户身份绑定验证 if(@ldap_bind($ldap_con, $user_dn, $input_password)) { $_SESSION['username'] = $input_username; header("Location: Startseite.php"); exit; } } } echo "Invalid Credential"; ldap_unbind($ldap_con); ?>
内容的提问来源于stack exchange,提问作者Etzi138
相关产品推荐
相关产品推荐

