如何在Flask-RESTful接口中实现LDAP身份认证功能?
LDAP认证逻辑实现方案
前置配置调整
生产环境禁止硬编码LDAP敏感配置,统一从环境变量读取,示例代码如下:
import os from ldap3 import SAFE_SYNC, Server, Connection, ALL, LDAPException # 从环境变量读取LDAP配置 LDAP_SERVER = os.getenv("LDAP_SERVER", "ldap://***.***.com") LDAP_ROOT_DN = os.getenv("LDAP_ROOT_DN", "dc=***,dc=com") LDAP_SERVICE_USER = os.getenv("LDAP_SERVICE_USER", "***") LDAP_SERVICE_PASSWORD = os.getenv("LDAP_SERVICE_PASSWORD", "***") # LDAP用户搜索的基础路径,通常是用户所在的组织单元,比如ou=users,dc=xxx,dc=com LDAP_USER_SEARCH_BASE = os.getenv("LDAP_USER_SEARCH_BASE", f"ou=users,{LDAP_ROOT_DN}") # LDAP用户名对应的属性字段,OpenLDAP场景通常为uid,AD场景通常为sAMAccountName LDAP_USERNAME_ATTR = os.getenv("LDAP_USERNAME_ATTR", "uid")
_is_ldap_authenticated 方法实现
核心逻辑:先用服务账号绑定LDAP服务器,搜索获取当前登录用户的完整DN,再用该DN和用户输入的密码尝试绑定,绑定成功则认证通过。
def _is_ldap_authenticated(self) -> bool: try: # 1. 连接LDAP服务器,用服务账号绑定 server = Server(LDAP_SERVER, get_info=ALL, connect_timeout=5) service_conn = Connection( server, user=LDAP_SERVICE_USER, password=LDAP_SERVICE_PASSWORD, client_strategy=SAFE_SYNC, auto_bind=True, ) except LDAPException as e: # 服务账号绑定失败,记录日志后返回认证失败 return False try: # 2. 搜索对应用户名的DN search_filter = f"({LDAP_USERNAME_ATTR}={self.parsed_username})" service_conn.search( search_base=LDAP_USER_SEARCH_BASE, search_filter=search_filter, attributes=["dn"] ) # 没有找到对应用户,认证失败 if len(service_conn.entries) != 1: return False user_dn = service_conn.entries[0].entry_dn finally: # 关闭服务账号连接 service_conn.unbind() try: # 3. 用用户的DN和输入的密码尝试绑定 user_conn = Connection( server, user=user_dn, password=self.parsed_password, client_strategy=SAFE_SYNC, auto_bind=True, connect_timeout=5 ) user_conn.unbind() return True except LDAPException: # 绑定失败,密码错误或账号异常 return False
生产环境适配注意事项
- 优先使用
ldaps://协议(默认端口636)传输LDAP请求,避免密码明文被拦截,如需兼容ldap协议建议开启StartTLS加密 - LDAP连接增加超时时间,避免接口请求长时间卡住影响服务可用性
- 禁止在日志中输出LDAP绑定的错误详情、用户密码等敏感信息
- 如果你使用的是微软AD服务,可以直接用
username@域后缀的格式拼接用户标识,跳过服务账号搜索步骤,直接绑定可提升性能 - 现有DB认证逻辑为明文密码比对,生产环境必须将DB存储的密码做bcrypt等不可逆哈希处理,比对时用哈希值校验,禁止明文存储用户密码
内容的提问来源于stack exchange,提问作者Amin Ba
相关产品推荐
相关产品推荐

