feat(ldap): 完善 LDAP 认证功能和安全性

- 添加 LDAP 配置类型定义,移除 any 类型
- 首次配置 LDAP 时强制要求设置绑定密码
- 根据认证类型区分登录标识验证(本地需邮箱,LDAP 允许用户名)
- 添加 LDAP 过滤器转义函数防止注入攻击
- 增加 LDAP 连接超时设置
- 添加账户来源冲突检查,防止 LDAP 覆盖本地账户
- 添加用户名冲突自动重命名机制
This commit is contained in:
RWDai
2026-01-04 11:18:28 +08:00
parent 612992fa1f
commit 64bfa955f4
8 changed files with 2147 additions and 2020 deletions

View File

@@ -6,7 +6,7 @@ import re
from datetime import datetime
from typing import Any, Dict, List, Literal, Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from ..core.enums import UserRole
@@ -15,19 +15,10 @@ from ..core.enums import UserRole
class LoginRequest(BaseModel):
"""登录请求"""
email: str = Field(..., min_length=3, max_length=255, description="邮箱地址")
email: str = Field(..., min_length=1, max_length=255, description="邮箱/用户名")
password: str = Field(..., min_length=1, max_length=128, description="密码")
auth_type: Literal["local", "ldap"] = Field(default="local", description="认证类型")
@classmethod
@field_validator("email")
def validate_email(cls, v):
"""验证邮箱格式"""
email_pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
if not re.match(email_pattern, v):
raise ValueError("邮箱格式无效")
return v.lower()
@classmethod
@field_validator("password")
def validate_password(cls, v):
@@ -37,6 +28,23 @@ class LoginRequest(BaseModel):
raise ValueError("密码不能为空")
return v
@model_validator(mode="after")
def validate_login(self):
"""根据认证类型校验并规范化登录标识"""
identifier = self.email.strip()
if self.auth_type == "local":
email_pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
if not re.match(email_pattern, identifier):
raise ValueError("邮箱格式无效")
self.email = identifier.lower()
else:
if not identifier:
raise ValueError("用户名/邮箱不能为空")
self.email = identifier
return self
class LoginResponse(BaseModel):
"""登录响应"""