47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
// shared/lib/auth/ldap.ts — LLDAP 认证
|
|
import { Client } from 'ldapts'
|
|
import type { LdapAuthResult } from './types'
|
|
|
|
export interface LdapConfig {
|
|
url: string
|
|
baseDn: string
|
|
adminDn?: string
|
|
adminPassword?: string
|
|
adminGroup?: string
|
|
}
|
|
|
|
// LDAP bind 认证用户
|
|
export async function ldapAuth(config: LdapConfig, username: string, password: string): Promise<LdapAuthResult> {
|
|
const client = new Client({ url: config.url, timeout: 5000 })
|
|
try {
|
|
const userDn = `uid=${username},ou=people,${config.baseDn}`
|
|
await client.bind(userDn, password)
|
|
return { success: true, username }
|
|
} catch (err: unknown) {
|
|
const message = err instanceof Error ? err.message : 'LDAP auth failed'
|
|
return { success: false, error: message }
|
|
} finally {
|
|
await client.unbind()
|
|
}
|
|
}
|
|
|
|
// 检查用户是否在 admin 组中
|
|
export async function checkAdminGroup(config: LdapConfig, username: string): Promise<boolean> {
|
|
if (!config.adminDn || !config.adminPassword || !config.adminGroup) return false
|
|
const client = new Client({ url: config.url, timeout: 5000 })
|
|
try {
|
|
await client.bind(config.adminDn, config.adminPassword)
|
|
const { searchEntries } = await client.search(`cn=${config.adminGroup},ou=groups,${config.baseDn}`, {
|
|
scope: 'sub',
|
|
filter: `(member=uid=${username},ou=people,${config.baseDn})`,
|
|
attributes: ['cn'],
|
|
sizeLimit: 1,
|
|
})
|
|
return searchEntries.length > 0
|
|
} catch {
|
|
return false
|
|
} finally {
|
|
await client.unbind()
|
|
}
|
|
}
|