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

@@ -155,6 +155,41 @@ export interface EmailTemplateResetResponse {
}
}
// LDAP 配置响应
export interface LdapConfigResponse {
server_url: string | null
bind_dn: string | null
base_dn: string | null
user_search_filter: string
username_attr: string
email_attr: string
display_name_attr: string
is_enabled: boolean
is_exclusive: boolean
use_starttls: boolean
}
// LDAP 配置更新请求
export interface LdapConfigUpdateRequest {
server_url: string
bind_dn: string
bind_password?: string
base_dn: string
user_search_filter?: string
username_attr?: string
email_attr?: string
display_name_attr?: string
is_enabled?: boolean
is_exclusive?: boolean
use_starttls?: boolean
}
// LDAP 连接测试响应
export interface LdapTestResponse {
success: boolean
message: string
}
// Provider 模型查询响应
export interface ProviderModelsQueryResponse {
success: boolean
@@ -477,13 +512,13 @@ export const adminApi = {
// LDAP 配置相关
// 获取 LDAP 配置
async getLdapConfig(): Promise<any> {
const response = await apiClient.get<any>('/api/admin/ldap/config')
async getLdapConfig(): Promise<LdapConfigResponse> {
const response = await apiClient.get<LdapConfigResponse>('/api/admin/ldap/config')
return response.data
},
// 更新 LDAP 配置
async updateLdapConfig(config: any): Promise<{ message: string }> {
async updateLdapConfig(config: LdapConfigUpdateRequest): Promise<{ message: string }> {
const response = await apiClient.put<{ message: string }>(
'/api/admin/ldap/config',
config
@@ -492,10 +527,10 @@ export const adminApi = {
},
// 测试 LDAP 连接
async testLdapConnection(config?: any): Promise<{ success: boolean; message: string }> {
const response = await apiClient.post<{ success: boolean; message: string }>(
async testLdapConnection(): Promise<LdapTestResponse> {
const response = await apiClient.post<LdapTestResponse>(
'/api/admin/ldap/test',
config || {}
{}
)
return response.data
}

View File

@@ -200,7 +200,7 @@ import { Label } from '@/components/ui/label'
import { Switch } from '@/components/ui/switch'
import { useToast } from '@/composables/useToast'
import { useLogger } from '@/composables/useLogger'
import { adminApi } from '@/api/admin'
import { adminApi, type LdapConfigUpdateRequest } from '@/api/admin'
const { success, error } = useToast()
const log = useLogger('LdapSettings')
@@ -257,7 +257,7 @@ async function loadConfig() {
async function handleSave() {
saveLoading.value = true
try {
const payload: Record<string, unknown> = {
const payload: LdapConfigUpdateRequest = {
server_url: ldapConfig.value.server_url,
bind_dn: ldapConfig.value.bind_dn,
base_dn: ldapConfig.value.base_dn,
@@ -268,9 +268,7 @@ async function handleSave() {
is_enabled: ldapConfig.value.is_enabled,
is_exclusive: ldapConfig.value.is_exclusive,
use_starttls: ldapConfig.value.use_starttls,
}
if (ldapConfig.value.bind_password) {
payload.bind_password = ldapConfig.value.bind_password
...(ldapConfig.value.bind_password && { bind_password: ldapConfig.value.bind_password }),
}
await adminApi.updateLdapConfig(payload)
success('LDAP 配置保存成功')