简单实例

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

一个简单的 Ldap 登录认证实例
configuration/ldap.py

class Ldap():
    ldap_host = "ldap.xxxxx.com"
    ldap_port = 389
    ldap_admin_user = "CN=HRSYS,OU=SysMAIL,OU=Headquarters,DC=xxxx,DC=COM"
    ldap_admin_password = "xxxx"
    ldap_base_search = "OU=Headquarters,DC=xxxxx,DC=COM"

ldapldap_util.py

from ldap3 import Server, Connection
from configuration.ldap import Ldap


def get_info_by_name(username):
    s = Server(host=Ldap.ldap_host, port=Ldap.ldap_port)
    adm_con = Connection(s, user=Ldap.ldap_admin_user, password=Ldap.ldap_admin_password)
    adm_con.bind()
    search_filter = '(sAMAccountName={})'.format(username)
    res = adm_con.search(search_base=Ldap.ldap_base_search, search_filter=search_filter, attributes=["mail"])
    if not res:
        return None

    entry = adm_con.response[0]
    mail = entry.get("raw_attributes").get("mail")

    return {
        "username": username,
        "mail": [x.decode('utf-8') for x in mail],
        "dn": entry["dn"]
    }

def ldap_auth(username, password):
    s = Server(host=Ldap.ldap_host, port=Ldap.ldap_port)
    userinfo = get_info_by_name(username)

    if userinfo is None:
        return None
    pwd_conn = Connection(s, user=userinfo.get("dn"), password=password, check_names=True)
    pwd_conn.bind()

    if int(pwd_conn.result.get("result")) != 0:
        return None
    return {
        "username": username,
    }