我们基于Django框架实现了MySQL数据库管理的web系统,为了能直接使用域用户登录,需要在Django中集成LDAP认证。一开始由于对Django和LDAP都不熟悉,也折腾了很长时间。
首先需要安装以下模块:
django-1.4.3
openldap-2.4.33
python-ldap-2.4.10 (需要有cyrus-sasl-devel.x86_64)
django-auth-ldap-1.1.2
安装完成后,django中的ldap完整配置如下:
import ldap
from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion, GroupOfNamesType
# Baseline configuration.
AUTH_LDAP_SERVER_URI = "ldap://cn.example.com"
AUTH_LDAP_BIND_DN = 'cn=username,ou=user,ou=ou1,ou=ou,dc=cn,dc=example,dc=com'
AUTH_LDAP_BIND_PASSWORD = 'password'
AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(
LDAPSearch("ou=user,ou=ou1,ou=ou,dc=cn,dc=example,dc=com",ldap.SCOPE_SUBTREE, "(&(objectClass=user)(sAMAccountName=%(user)s))"),
LDAPSearch("ou=user,ou=ou2,ou=ou,dc=cn,dc=example,dc=com",ldap.SCOPE_SUBTREE, "(&(objectClass=user)(sAMAccountName=%(user)s))"),
)
# Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=groups,ou=ou,dc=cn,dc=example,dc=com",
ldap.SCOPE_SUBTREE, "(objectClass=group)"
)
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr="cn")
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "first_name",
"last_name": "last_name",
"email": "mail"
}
AUTH_LDAP_MIRROR_GROUPS=True
AUTHENTICATION_BACKENDS = (
'django_auth_ldap.backend.LDAPBackend',
'django.contrib.auth.backends.ModelBackend',
)
其中LDAPSearchUnion是为了能在不同的ou中搜索用户,没有这个需求的话直接LDAPSearch就行。
AUTH_LDAP_MIRROR_GROUPS=True 这个参数是为了在用户登录的时候把用户的域组关系也获取并记录下
来。不过开启这个参数会带来另外一个问题:每次用户登录时,都会把用户的组关系删除,重新从ldap中进行同步。由于我们的系统中除了域组还有些自定义的组关系,这样一来自定义组的用户关系就不能持久保留了。按照我们的需求,其实只希望在用户第一次登录的时候同步组关系,以后的登录并不需要。这个需求可以通过对django-auth-ldap的源码进行微调来实现。
在django-auth-ldap源码包的backend.py文件中,以下代码决定了用户登录时的行为:
def _get_or_create_user(self, force_populate=False):
"""
Loads the User model object from the database or creates it if it
doesn't exist. Also populates the fields, subject to
AUTH_LDAP_ALWAYS_UPDATE_USER.
"""
save_user = False
username = self.backend.ldap_to_django_username(self._username)
self._user, created = self.backend.get_or_create_user(username, self)
self._user.ldap_user = self
self._user.ldap_username = self._username
should_populate = force_populate or self.settings.ALWAYS_UPDATE_USER or created
if created:
logger.debug("Created Django user %s", username)
self._user.set_unusable_password()
save_user = True
if should_populate:
logger.debug("Populating Django user %s", username)
self._populate_user()
save_user = True
if self.settings.MIRROR_GROUPS:
self._mirror_groups()
在其中进行组信息同步的地方增加一个条件,即可实现只在创建用户时同步组信息的需求:
if self.settings.MIRROR_GROUPS and created:
self._mirror_groups()
修改好以后重新编译安装django-auth-ldap,这样就可以完整地实现我们的需求了。