Live2D

使用python 接入LDAP验证系统实践记录

LDAP简介

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

LDAP基本概念

LDAP的目的是为各种软件提供统一标准的认证机制,所有软件就可以不再用独有的用户管理方法,而是通过这种统一的认证机制进行用户认证。

LDAP基本结构

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。

flask项目对于LDAP有ldap3库

通过 ldap3 构造处理类 配置即可,配置一般向公司的运维人员要
代码如下:

class LDAPUtil(object):
    def __init__(self, ldap_host=None, port=None, base_dn=None, base_user=None, base_password=None):
        self.base_dn = base_dn
        try:
            server = Server(ldap_host, port, get_info=ALL)
            self.ldapconn = Connection(server, user=base_user, password=base_password, auto_bind=False)
            self.ldapconn.bind()
        except Exception as e:
            print(e)

    def ldap_search_dn(self, type_check="uid", value=None):
        obj = self.ldapconn
        search_base = self.base_dn
        search_scope = SUBTREE
        search_filter = f"({type_check}={value})"
        try:
            obj.search(search_base, search_filter, search_scope, attributes=['cn', 'uid', ])  # , paged_size=1
            if len(obj.response) == 1:
                return obj.response[0]['dn']
            else:
                return None
        except Exception as e:
            print(e)

    def authentication_by(self, type_check="uid", value=None, passwd=None):
        if not value or not passwd:
            return False
        obj = self.ldapconn
        bind_dn = self.ldap_search_dn(type_check=type_check, value=value)
        print(bind_dn)
        try:
            if obj.rebind(bind_dn, passwd):  # 可以使用搜索得到的绑定用户名uid,即可省去自己构造
                return True
            else:
                return False
        except Exception as e:
            print('e:' + str(e))
ldap = LDAPUtil(ldap_host, int(port), base_dn, base_user, base_password)
# 首先可以通过搜索获得正确格式的名称
search_ldap_by_uid = ldap.ldap_search_dn(type_check="uid", value="name")
search_ldap_by_mail = ldap.ldap_search_dn(type_check="mail", value="name@test.com")
search_ldap_by_cn = ldap.ldap_search_dn(type_check="cn", value="Name")
# 然后就可以传入不同类型的用户名进行验证了,如search_ldap_by_uid是查询得到的正确格式的用户id,search_ldap_by_mail是邮箱格式的用户名,search_ldap_by_cn是用户名
authentication_result = ldap.authentication_by(type_check=search_ldap_by_uid, value="name", passwd="password")  # BOOL 是否验证成功

另外,也可以通过flask_ldap3_login这个库进行配置即可使用,flask_ldap3_login对ldap3进行了封装,直接配置就可以使用,比较方便
代码如下:

from flask_ldap3_login import LDAP3LoginManager


ldap_manager = LDAP3LoginManager()
ldap_manager.init_config({"LDAP_HOST": LDAP_HOST,  # 形如'ldap://xxx.xxx.xxx.xxx:389'
                          "LDAP_BASE_DN": LDAP_BASE_DN,  # 形如'dc=test,dc=com'
                          "LDAP_USER_LOGIN_ATTR": LDAP_USER_LOGIN_ATTR,  # 'uid'  # 'cn' 'mail'
                          "LDAP_USER_SEARCH_SCOPE": LDAP_USER_SEARCH_SCOPE,  # 'SUBTREE'
                          "LDAP_BIND_USER_DN": LDAP_BIND_USER_DN,  # 形如'cn=admin,dc=test,dc=com'
                          "LDAP_BIND_USER_PASSWORD": LDAP_BIND_USER_PASSWORD,  # admin的密码
                          "LDAP_ALWAYS_SEARCH_BIND": LDAP_ALWAYS_SEARCH_BIND,  # 一般是True
                          "LDAP_GROUP_OBJECT_FILTER": LDAP_GROUP_OBJECT_FILTER,  # "(objectclass=posixGroup)" 或者 "(objectclass=groupOfNames)" 这里踩了坑,需要配置上
                          })
# 然后就可以直接调用ldap_manager进行验证了
authentication_result = ldap_manager.authenticate("uid", "password")  # authentication_result .status.value = 2 则表示验证成功

以上就是此次接入LDAP的记录。

posted @ 2022-10-29 15:19  含光掠影  阅读(798)  评论(0)    收藏  举报