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 相关文章推荐
简单的编程0基础下Python入门指引
Apr 01 Python
Python中使用gzip模块压缩文件的简单教程
Apr 08 Python
基于python中staticmethod和classmethod的区别(详解)
Oct 24 Python
详解django三种文件下载方式
Apr 06 Python
解决Python print 输出文本显示 gbk 编码错误问题
Jul 13 Python
解决python写入带有中文的字符到文件错误的问题
Jan 31 Python
在windows下使用python进行串口通讯的方法
Jul 02 Python
解决python有时候import不了当前的包问题
Aug 28 Python
Django admin禁用编辑链接和添加删除操作详解
Nov 15 Python
将python包发布到PyPI和制作whl文件方式
Dec 25 Python
python GUI库图形界面开发之PyQt5不规则窗口实现与显示GIF动画的详细方法与实例
Mar 09 Python
Python控制台输出俄罗斯方块的方法实例
Apr 17 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与XML的PDF文档生成技术
2006/10/09 PHP
PHP传参之传值与传址的区别
2015/04/24 PHP
PHP实现的XML操作类【XML Library】
2016/12/29 PHP
完美解决php 导出excle的.csv格式的数据时乱码问题
2017/02/18 PHP
php实现微信企业号支付个人的方法详解
2017/07/26 PHP
js 获取中文拼音,Select自动匹配字母获取值的代码
2009/09/23 Javascript
JavaScript Timer实现代码
2010/02/17 Javascript
基于jquery的网页SELECT下拉框美化代码
2010/10/28 Javascript
页面定时刷新(1秒刷新一次)
2013/11/22 Javascript
JS实现仿微博可关闭弹出层效果
2015/09/21 Javascript
一些实用性较高的js方法
2016/04/19 Javascript
javascript html5摇一摇功能的实现
2016/04/19 Javascript
Winform客户端向web地址传参接收参数的方法
2016/05/17 Javascript
jQuery原理系列-常用Dom操作详解
2016/06/07 Javascript
BootStrap数据表格实例代码
2017/09/13 Javascript
vuejs实现本地数据的筛选分页功能思路详解
2017/11/15 Javascript
JS在if中的强制类型转换方式
2018/07/15 Javascript
js使用formData实现批量上传
2020/03/27 Javascript
富文本编辑器vue2-editor实现全屏功能
2019/05/26 Javascript
Vue移动端右滑屏幕返回上一页附源码下载
2019/06/26 Javascript
微信小程序wx.request拦截器使用详解
2019/07/09 Javascript
jquery向后台提交数组的代码分析
2020/02/20 jQuery
vue2.x 对象劫持的原理实现
2020/04/19 Javascript
JS数组转字符串实现方法解析
2020/09/04 Javascript
js实现淘宝浏览商品放大镜功能
2020/10/28 Javascript
[02:24]DOTA2亚洲邀请赛 NAVI战队出场宣传片
2015/02/07 DOTA
[51:36]EG vs VP 2018国际邀请赛淘汰赛BO3 第一场 8.24
2018/08/25 DOTA
Python温度转换实例分析
2018/01/17 Python
Python 编码规范(Google Python Style Guide)
2018/05/05 Python
对Python模块导入时全局变量__all__的作用详解
2019/01/11 Python
scrapy中如何设置应用cookies的方法(3种)
2020/09/22 Python
惊艳的手工时装首饰:Migonne Gavigan
2018/02/23 全球购物
Jacques Lemans德国:奥地利钟表品牌
2019/12/26 全球购物
2014年初一班主任工作总结
2014/11/08 职场文书
java高级用法JNA强大的Memory和Pointer
2022/04/19 Java/Android
MySQL数据库之内置函数和自定义函数 function
2022/06/16 MySQL