python使用ldap进行用户认证

这两天做sso,用到了ldap,这个东西只见过没涉及过,最近还是看了小两天,记录一下

LDAP轻型目录访问协议,可以就把他看成一个轻量级数据库,那么现在系统已经有mysql等数据库了,为什么还要用这个,有两个原因:
1.ldap server使用的是tree结构,查询很快
2.ldap协议比较通用,很多语言和环境对他有支持,方便不同语言及环境间的对接

包版本ldap3==2.9.1
这个东西django其实有一个专门的第三方库,配置一下就行了,但是目前架构没有使用django自带的用户系统,所以不好适配就直接手写了

from ldap3 import Server, Connection, ALL, MODIFY_ADD, MODIFY_REPLACE, MODIFY_DELETE


class Connect_ldap:

    def __init__(self):  # 初始化
        self.server = '127.0.0.1'  # ldap服务器地址
        self.user = 'cn=admin,dc=XXX,dc=com'  # Bind DN or user
        self.base_dn = 'dc=XXX,dc=com'  # base_dn
        self.pwd = 'XXXXX'  # 密码
        self.port = 389  # 端口

    def connect(self):  # 连接ldap服务
        server = Server(host=self.server, port=self.port, get_info=ALL)
        conn = Connection(server=server, user=self.user, password=self.pwd, auto_bind=True)
        return conn

    def get_user(self) -> bool:
        """
        用户查询
        :return:
        """
        conn = self.connect()
        dn_look_path = 'ou=Users,dc=XXX,dc=com'
        find_res = conn.search(dn_look_path,
                               '(&(cn=xxxx)(userPassword=xxxxx))')  # cn is username && userPassword is password
        return find_res

    def add_user(self, username, password) -> bool:
        """
        用户添加
        :param username: 用户名
        :param password: 密码
        :return:
        """
        conn = self.connect()
        add_res = conn.add(f"cn={username},ou=Users,dc=XXX,dc=com",
                           object_class=['inetOrgPerson', 'top'],  # 类型
                           attributes={'sn': username, 'userPassword': password})  # 属性
        return add_res

    def delete_user(self, username):
        """
        用户删除
        :param username
        :return:
        """
        conn = self.connect()
        delete_res = conn.delete(f"cn={username},ou=Users,dc=XXX,dc=com")
        return delete_res

    def modify_user(self, username, password) -> bool:
        """
        用户修改密码
        :param username:
        :param password:
        :return:
        """
        conn = self.connect()
        modify_res = conn.modify(f"cn={username},ou=Users,dc=XXX,dc=com",
                                 {"userPassword": [(MODIFY_REPLACE, [password])]})
        return modify_res


if __name__ == "__main__":
    a = Connect_ldap()
    res = a.add_user('xxxx2', '123456')
    print(res)

上面这个类就大致是对接ldap代码了,涉及到用户的增删改查
当然这里ldap是为了sso,也就是其它系统的免登录操作,所以自身用户系统的数据库还是少不了了

ldap server的话我是用docker直接拉下来的,也比较方便

docker run -itd --privileged=true --net=host --name my-ldap 
-v /home/xxx_ldap/database:/var/lib/ldap 
-v /home/xxx_ldap/config:/etc/ldap/slapd.d 
--env LDAP_ORGANISATION="XXX" 
--env LDAP_DOMAIN="XXX.com" 
--env LDAP_ADMIN_PASSWORD="XXXXX" 
--detach osixia/openldap:latest

ldap管理也是docker拉的

docker run -d --privileged=true --net=host --name my-phpldapadmin 
--env PHPLDAPADMIN_HTTPS=true 
--env PHPLDAPADMIN_LDAP_HOSTS=127.0.0.1 
--detach osixia/phpldapadmin

这里80端口给占了,改成81还是没法访问,用https可以了,应该是PHPLDAPADMIN_HTTPS参数的事情
登录进去后创建ou,这里ou是Users,具体创建参照这个大佬

以下是系统(前后端分离模式)的ldap流程:

1.首先将用户输入账号、密码信息发给ldap服务器进行认证
2.如果ldap认证通过,我们去查询数据库中是否已存在此账号的用户,若存在,进行权限校验等操作,若不存在,则先在数据库中创建此用户,随后直接登陆
3.如果ldap认证失败,返回错误即可

感觉可能叙述的还不太清楚,因为本身资料就非常零碎,找了好多有些都忘了在哪看的,如果有疑问的话可以留言