Python使用LDAP做用户认证的方法


Posted in Python onJune 20, 2019

LDAP(Light Directory Access Portocol)是轻量目录访问协议,基于X.500标准,支持TCP/IP。

LDAP目录以树状的层次结构来存储数据。每个目录记录都有标识名(Distinguished Name,简称DN),用来读取单个记录,

一般是这样的:

cn=username,ou=people,dc=test,dc=com

几个关键字的含义如下:

  • base dn:LDAP目录树的最顶部,也就是树的根,是上面的dc=test,dc=com部分,一般使用公司的域名,也可以写做o=test.com,前者更灵活一些。
  • dc::Domain Component,域名部分。
  • ou:Organization Unit,组织单位,用于将数据区分开。
  • cn:Common Name,一般使用用户名。
  • uid:用户id,与cn的作用类似。
  • sn:Surname, 姓。
  • rdn:Relative dn,dn中与目录树的结构无关的部分,通常存在cn或者uid这个属性里。

所以上面的dn代表一条记录,代表一位在test.com公司people部门的用户username。

python-ldap

python一般使用python-ldap库操作ldap,文档:https://www.python-ldap.org/en/latest/index.html。

下载:

pip install python-ldap

还要安装一些环境,ubuntu:

apt-get install build-essential python3-dev python2.7-dev \
  libldap2-dev libsasl2-dev slapd ldap-utils python-tox \
  lcov valgrind

CentOS:

yum groupinstall "Development tools"
yum install openldap-devel python-devel

获取LDAP地址后即可与LDAP建立连接:

import ldap
ldapconn = ldap.initialize('ldap://192.168.1.111:389')

绑定用户,可用于用户验证,用户名必须是dn: 

ldapconn.simple_bind_s('cn=username,ou=people,dc=test,dc=com', pwd)

成功认证时会返回一个tuple:

(97, [], 1, [])

验证失败会报异常ldap.INVALID_CREDENTIALS:

{'desc': u'Invalid credentials'}

注意验证时传空值验证也是可以通过的,注意要对dn和pwd进行检查。

查询LDAP用户信息时,需要登录管理员RootDN帐号:

ldapconn.simple_bind_s('cn=admin,dc=test,dc=com', 'adminpwd')
searchScope = ldap.SCOPE_SUBTREE
searchFilter = 'cn=username'
base_dn = 'ou=people,dc=test,dc=com'
print ldapconn.search_s(base_dn, searchScope, searchFilter, None)

添加用户add_s(dn, modlist),dn为要添加的条目dn,modlist为存储信息:

dn = 'cn=test,ou=people,dc=test,dc=com'
modlist = [
  ('objectclass', ['person', 'organizationalperson'],
  ('cn', ['test']),
  ('uid', [''testuid]),
  ('userpassword', ['pwd']),
]
result = ldapconn.add_s(dn, modlist)

添加成功会返回元组:

(105, [], 2, [])

失败会报ldap.LDAPError异常

Django使用LDAP验证

一个很简单的LDAP验证Backend:

import ldap
class LDAPBackend(object):
  """
  Authenticates with ldap.
  """
  _connection = None
  _connection_bound = False
 
  def authenticate(self, username=None, passwd=None, **kwargs):
    if not username or not passwd:
      return None
    if self._authenticate_user_dn(username, passwd):
      user = self._get_or_create_user(username, passwd)
      return user
    else:
      return None
 
  @property
  def connection(self):
    if not self._connection_bound:
      self._bind()
    return self._get_connection()
 
  def _bind(self):
    self._bind_as(
      LDAP_CONFIG['USERNAME'], LDAP_CONFIG['PASSWORD'], True
    )
 
  def _bind_as(self, bind_dn, bind_password, sticky=False):
    self._get_connection().simple_bind_s(
      bind_dn, bind_password
    )
    self._connection_bound = sticky
 
  def _get_connection(self):
    if not self._connection:
      self._connection = ldap.initialize(LDAP_CONFIG['HOST'])
    return self._connection
 
  def _authenticate_user_dn(self, username, passwd):
    bind_dn = 'cn=%s,%s' % (username, LDAP_CONFIG['BASE_DN'])
    try:
      self._bind_as(bind_dn, passwd, False)
      return True
    except ldap.INVALID_CREDENTIALS:
      return False
 
  def _get_or_create_user(self, username, passwd):
    # 获取或者新建User
    return user

不想自己写的话,django与flask都有现成的库:

  • django-ldap
  • flask-ldap

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python列表去重的二种方法
Feb 14 Python
Python使用defaultdict读取文件各列的方法
May 11 Python
浅述python中深浅拷贝原理
Sep 18 Python
python程序快速缩进多行代码方法总结
Jun 23 Python
python并发编程多进程之守护进程原理解析
Aug 20 Python
python except异常处理之后不退出,解决异常继续执行的实现
Apr 25 Python
Pytorch 解决自定义子Module .cuda() tensor失败的问题
Jun 23 Python
Python学习工具jupyter notebook安装及用法解析
Oct 23 Python
Pycharm配置lua编译环境过程图解
Nov 28 Python
使用Python爬取Json数据的示例代码
Dec 07 Python
Python实现简繁体转换
Jun 07 Python
python模板入门教程之flask Jinja
Apr 11 Python
Python OpenCV中的resize()函数的使用
Jun 20 #Python
python中的句柄操作的方法示例
Jun 20 #Python
使用python获取(宜宾市地震信息)地震信息
Jun 20 #Python
一篇文章了解Python中常见的序列化操作
Jun 20 #Python
python集合是否可变总结
Jun 20 #Python
Django如何自定义model创建数据库索引的顺序
Jun 20 #Python
pyqt 多窗口之间的相互调用方法
Jun 19 #Python
You might like
一个简单的自动发送邮件系统(三)
2006/10/09 PHP
PHP7中I/O模型内核剖析详解
2019/04/14 PHP
如何解决PHP获取不到SESSION信息之一般情况
2019/10/10 PHP
基于Laravel(5.4版本)的基本增删改查操作方法
2019/10/11 PHP
PHP实现限制域名访问的实现代码(本地验证)
2020/09/13 PHP
Javascript的严格模式strict mode详细介绍
2014/06/06 Javascript
javaScript中Math()函数注意事项
2015/06/18 Javascript
分享我的jquery实现下拉菜单心的
2015/11/29 Javascript
基于javascript实现checkbox复选框实例代码
2016/01/28 Javascript
获取JavaScript异步函数的返回值
2016/12/21 Javascript
Angular2利用组件与指令实现图片轮播组件
2017/03/27 Javascript
如何在vue中使用ts的示例代码
2018/02/28 Javascript
浅谈Node.js 沙箱环境
2018/05/15 Javascript
说说node中的可读流和可写流的区别
2018/06/01 Javascript
js设计模式之代理模式及订阅发布模式实例详解
2019/08/15 Javascript
[00:56]PWL开团时刻DAY8——追追追追追!
2020/11/09 DOTA
Kears+Opencv实现简单人脸识别
2019/08/28 Python
PHP统计代码行数的小代码
2019/09/19 Python
python从zip中删除指定后缀文件(推荐)
2019/12/05 Python
django有外键关系的两张表如何相互查找
2020/02/10 Python
python实现梯度法 python最速下降法
2020/03/24 Python
HTML5里autofocus自动聚焦属性使用介绍
2016/06/22 HTML / CSS
美国家用和厨房电器销售网站:Appliances Connection
2020/01/24 全球购物
c/c++某大公司的两道笔试题
2014/02/02 面试题
EJB3推出JPA的原因
2013/10/16 面试题
临床医师个人自我评价
2014/04/06 职场文书
学习雷锋倡议书
2014/04/15 职场文书
团日活动总结范文
2014/04/25 职场文书
主持人演讲稿
2014/05/13 职场文书
小学生关于梦想的演讲稿
2014/08/22 职场文书
2014个人反腐倡廉思想汇报
2014/09/15 职场文书
病人写给医生的感谢信
2015/01/23 职场文书
幼儿园大班开学寄语(2015秋季)
2015/05/27 职场文书
2016年全国助残日活动总结
2016/04/01 职场文书
pytorch 一行代码查看网络参数总量的实现
2021/05/12 Python
MySQL中IF()、IFNULL()、NULLIF()、ISNULL()函数的使用详解
2021/06/26 MySQL