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使用Flask框架获取当前查询参数的方法
Mar 21 Python
python实现批量修改文件名代码
Sep 10 Python
详解Python核心对象类型字符串
Feb 11 Python
详解python 注释、变量、类型
Aug 10 Python
python中map的基本用法示例
Sep 10 Python
pycharm中使用anaconda部署python环境的方法步骤
Dec 19 Python
python学生管理系统开发
Jan 30 Python
使用python绘制二元函数图像的实例
Feb 12 Python
python3使用matplotlib绘制条形图
Mar 25 Python
python基于event实现线程间通信控制
Jan 13 Python
Python tkinter实现简单加法计算器代码实例
May 13 Python
python更新数据库中某个字段的数据(方法详解)
Nov 18 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
关于php正则匹配汉字的方法介绍
2013/04/25 PHP
php中如何判断一个网页请求是ajax请求还是普通请求
2013/08/10 PHP
使用php实现网站验证码功能【推荐】
2017/02/09 PHP
ThinkPHP3.2框架自定义配置和加载用法示例
2018/06/14 PHP
JS实现悬浮移动窗口(悬浮广告)的特效
2013/03/12 Javascript
jQuery 遍历- 关于closest() 的方法介绍以及与parents()的方法区别分析
2013/04/26 Javascript
jQuery使用元素属性attr赋值详解
2015/02/27 Javascript
探究JavaScript函数式编程的乐趣
2015/12/14 Javascript
JavaScript实现瀑布流布局
2020/06/28 Javascript
jQuery div拖拽用法实例
2016/01/14 Javascript
jQuery内容折叠效果插件用法实例分析(附demo源码)
2016/04/28 Javascript
jQuery实现的简单拖拽功能示例
2016/09/13 Javascript
简单理解js的冒泡排序
2016/12/19 Javascript
js for循环倒序输出数组元素的实例
2017/03/01 Javascript
简述vue中的config配置
2018/01/23 Javascript
RequireJS用法简单示例
2018/08/20 Javascript
重学JS之显示强制类型转换详解
2019/06/30 Javascript
Postman环境变量全局变量使用方法详解
2020/08/13 Javascript
[01:54]TI珍贵瞬间系列(三):翻盘
2020/08/28 DOTA
获取Django项目的全部url方法详解
2017/10/26 Python
python 循环数据赋值实例
2019/12/02 Python
Python+Selenium+phantomjs实现网页模拟登录和截图功能(windows环境)
2019/12/11 Python
Python字典中的值为列表或字典的构造实例
2019/12/16 Python
python 微信好友特征数据分析及可视化
2020/01/07 Python
使用openCV去除文字中乱入的线条实例
2020/06/02 Python
python中Array和DataFrame相互转换的实例讲解
2021/02/03 Python
html5教程调用绘图api画简单的圆形代码分享
2013/12/04 HTML / CSS
利用HTML5 Canvas制作键盘及鼠标动画的实例分享
2016/03/15 HTML / CSS
美国最大的无人机经销商:DroneNerds
2018/03/20 全球购物
美国肌肉和力量商店:Muscle & Strength
2019/06/22 全球购物
.NET里面如何取得当前的屏幕分辨率
2012/12/06 面试题
上班迟到检讨书
2014/01/10 职场文书
杨善洲观后感
2015/06/04 职场文书
安全第一课观后感
2015/06/18 职场文书
奖学金主要事迹范文
2015/11/04 职场文书
深入理解margin塌陷和margin合并的解决方案
2021/06/26 HTML / CSS