以前有需求要作一个django+ldap用户管理的简单接口,研究了好几个模块,最后终于能实现django用ldap作用户认证了。也是本身的水平有限吧,作了好长时间,如今就和你们分享一下这个过程吧。最终是有两种方法实现这个认证过程,一种是经过django-python3-ldap实现的,一种是本身写了一个简单的。我下面有个示例程序在github上面,这个程序是两个方法都能用,并且我放到了一个django的app下。你们能够下载下来看看。css
具体以下:
python pip信息:html
bogon:ldapdemo hongzhi.wang$ pip list|egrep -i 'django|ldap' Django 1.8.11 django-auth-ldap 1.2.9 django-bootstrap-form 3.2.1 django-celery 3.1.16 django-crontab 0.7.1 django-python3-ldap 0.9.11 djangorestframework 3.6.2 ldap3 1.4.0 python-ldap 2.4.32
ldap 相关信息(在我本身的虚拟机上面搭的):node
192.168.3.3:389 dn: cn=user03,ou=People,dc=node1,dc=com secret:555 dn: cn=user02,ou=People,dc=node1,dc=com secret:555 dn: cn=user01,ou=People,dc=node1,dc=com secret:555
user02的详细信息python
dn: cn=user02,ou=People,dc=node1,dc=com objectClass: posixAccount objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person homeDirectory: /home/user02 loginShell: /bin/bash uid: user02 cn: user02 uidNumber: 10002 gidNumber: 100 sn: user02 mail: user02@qq.com userPassword:: e1NTSEF9WEZXOWMxaFZFMjVaK3JnV3Q3a1FDWW0wdWxjRVZrVk8=
示例程序地址在此:https://github.com/WisWang/ldapdemojquery
目录结构以下:git
bogon:PycharmProjects hongzhi.wang$ tree ldapdemo/|grep -v pyc ldapdemo/ ├── db.sqlite3 ├── ldapdemo │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ ├── wsgi.py ├── manage.py ├── my_ldap_auth │ ├── __init__.py │ ├── admin.py │ ├── django_python3_ldap_settings.py │ ├── ldap_tool.py │ ├── migrations │ │ ├── __init__.py │ ├── models.py │ ├── mysettings.py │ ├── tests.py │ ├── urls.py │ ├── views.py ├── static │ ├── css │ │ ├── bootstrap.css │ │ ├── bootstrap.min.css │ │ └── custom.css │ └── js │ ├── bootstrap.js │ ├── bootstrap.min.js │ └── jquery-2.2.2.js └── templates ├── home.html ├── ldap_auth.html └── login_content.html
本次还用了django-python3-ldapgithub
基本思路就是经过python-ldap这个模块本身封装了一个类,而后实现各类用到的方法,
认证过程就是拿到用户名密码后,先经过这个ldapdemo/my_ldap_auth/ldap_tool.py
里的以下方法验证用户名存不存在,存在返回这个用户的dn(这种方法缺点是用户名在这个basedn下面必须惟一,不过能够经过让用户输入部门名输入到后台,而后再search的时候添加ou筛选就能实现用户在不一样部门可是用户名相同的认证,本文就再多作叙述了。)sql
def check_user(self, username): self.conn.simple_bind_s(USER, PASSWORD) filter = '(uid=%s)' % username attrs = ['sn', 'uid'] ret = self.conn.search_s(BASE_DN, ldap.SCOPE_SUBTREE, filter, attrs) if ret: return ret[0][0] else: return False
拿到用户名后self.conn.simple_bind_s(dn,userpass)
这样去server端检查用户名,密码。
而后就是这段代码了ldapdemo/my_ldap_auth/views.py
:django
ldaptool = LdapTool() res = ldaptool.check_pass(username,password) #res这个放回值是我自定义的,详见代码吧 if res == 0: user = User.objects.filter(username=username) if not user: u = User.objects.create_user(username=username, password="asdf1234") else: u = user[0] u.set_password("asdf1234") u.save() user = authenticate(username=username, password='asdf1234') login(request, user) return HttpResponseRedirect('/') elif res == 1: err_msg = "username not found" else: err_msg = "password wrong" return render(request, 'ldap_auth.html', {'err_msg': err_msg, })
基本思路就是ldap验证经过之后,检查django默认的User表有没有这个用户,没有就建立,而后把这个用户登陆。(这个是每次有用户认证都会和ldapserver创建一个链接,以前是在django启动的时候我就创建一个链接,各有优缺点吧。)bootstrap
这个基本就是按照这个django-python3-ldap在github上面那个readme来作的,可是遇到些问题,我把原来的代码改了一处,就能用了,可是感受限制有些多,下面就来讲一下吧。
在配置文件中有以下配置
# The LDAP username and password of a user for authenticating the `ldap_sync_users` # management command. Set to None if you allow anonymous queries. LDAP_AUTH_CONNECTION_USERNAME = "admin" LDAP_AUTH_CONNECTION_PASSWORD = "secret"
它./manage.py ldap_sync_users
这样同步用户的时候,因为这个配置一下配置:
# The LDAP search base for looking up users. LDAP_AUTH_SEARCH_BASE = "ou=people,dc=example,dc=com" # User model fields mapped to the LDAP # attributes that represent them. LDAP_AUTH_USER_FIELDS = { "username": "uid", "first_name": "givenName", "last_name": "sn", "email": "mail", }
这个admin用户
的dn就会变成"uid=admin,ou=people,dc=example,dc=com"
不是咱们但愿的"uid=admin,dc=example,dc=com"
由于通常admin是有没有ou这个属性的(个人理解是这样),这个同步成功不了。
我把site-packages/django_python3_ldap/ldap.py
这个文件其中第120行左右的内容改为以下:
if kwargs: password = kwargs.pop("password") if username != "cn=admin,dc=node1,dc=com": username = import_func(settings.LDAP_AUTH_FORMAT_USERNAME)(kwargs) # Make the connection. print "***",username # 这样就能够看到他这个模块加工后的dn了,打印出来方便本身检查问题,若是认证不了加上这个基本不少问题都能解决,我还停留在print debug阶段呢,之后要设置断点来debug了O(∩_∩)O~
这样就能够经过这个admin来同步用户信息了。
本文我本身实现的认证是经过python-ldap实现的,不过ldap3是更pythonic的模块,我研究了一下,其实彻底能够替代python-ldap这个模块的,不过我这个都写完了,ldap3的使用就放在之后吧,我再研究的过程当中还在stackoverflow上面问过经过python ldap的模块在不知道用户密码的状况下经过admin给用户重置密码的方法呢,问题连接,最后仍是我本身仔细看了官方文档,给解决了,这里面有python-ldap和ldap3的官方文档链接,你们能够看看。个人blog开始有我本身的联系方式啥的,有问题随时问哈。