核心是分清认证与授权阶段,并用RequireAll/RequireNone嵌套实现布尔逻辑:必须启用mod_ldap和mod_authnz_ldap,AuthLDAPURL需严格匹配baseDN、attribute、scope、filter,组比对须设AuthLDAPGroupAttribute member且开启AuthLDAPGroupAttributeIsDN on。
要在虚拟主机中用 mod_authnz_ldap 实现复杂组权限控制,核心不是堆叠更多指令,而是理清“认证”和“授权”两个阶段的分工,并精准控制 require 块的嵌套逻辑。apache 本身不支持 ldap 层面的布尔表达式(如 and、not),必须靠 <requireall></requireall> 和 <requirenone></requirenone> 组合实现。
确保模块已启用且依赖完整
Apache 默认不加载 LDAP 相关模块,缺一不可:
- 必须同时启用
mod_ldap(负责连接与缓存)和mod_authnz_ldap(提供认证与授权接口) - Debian/Ubuntu:运行
a2enmod ldap authnz_ldap,注意顺序——先ldap,再authnz_ldap - CentOS/RHEL:确认
/etc/httpd/conf.modules.d/中两行已取消注释:LoadModule ldap_module modules/mod_ldap.soLoadModule authnz_ldap_module modules/mod_authnz_ldap.so - 重启前务必执行
apachectl -t;若报Cannot load mod_ldap.so,说明系统缺少openldap-clients(RHEL)或libldap2-dev(Debian)
AuthLDAPURL 必须严格匹配目录结构
这个 URL 是 LDAP 搜索语句,不是普通链接,格式固定为:protocol://host:port/baseDN?attribute?scope?filter
-
baseDN 必须是用户实际所在 OU,例如
OU=Employees,DC=example,DC=com,不能填根域DC=example,DC=com(性能差且易匹配失败) -
attribute 要与登录名字段一致:AD 用
sAMAccountName或userPrincipalName,OpenLDAP/FreeIPA 通常用uid -
scope 推荐
sub(子树搜索),one只查一级,base只查节点自身 -
filter 不可省略,AD 常用
(objectClass=user),OpenLDAP 推荐(objectClass=inetOrgPerson)
组权限逻辑必须用 RequireAll/RequireNone 显式构造
Require ldap-group 默认是“或”语义,要实现“且”“非”,必须嵌套:
- “属于 A 组 且 属于 B 组” → 外层
<requireall></requireall>,内含两个Require ldap-group - “属于 A 组 但不属于 B 组” →
<requireall><require ldap-group a><requirenone><require ldap-group b></require></requirenone></require></requireall> - “禁止 C 组所有成员” → 单独用
<requirenone><require ldap-group c></require></requirenone> - 注意:
RequireNone在 Apache 2.4.10+ 才完整支持;旧版本需升级或改用数据库映射方案
组成员比对必须启用 DN 级别匹配
LDAP 组成员关系靠 member(或 uniqueMember)属性存储的是用户完整 DN,不是用户名字符串:
- 必须设置
AuthLDAPGroupAttribute member(AD 常用)或uniqueMember(FreeIPA/389DS) - 必须开启
AuthLDAPGroupAttributeIsDN on,否则 Apache 会把登录名当字符串去比对member值,永远失败 - 验证方法:用
ldapsearch -x -H ldaps://ldap.example.com -b "cn=admins,ou=groups,dc=example,dc=com" member,检查返回值是否包含目标用户的完整 DN,如uid=john,ou=Users,dc=example,dc=com

















