feat(ldap): Active Directory 双目录支持与 Docker 构建优化

- 新增 ldap_ad.go,支持 AD 密码编码、字段映射与目录类型判断
- 重构 ldap/ldap_users/ldap_ou,兼容 OpenLDAP 与 AD 登录、导入、OU 浏览
- 前端系统设置增加目录类型选择与 AD 配置项
- Dockerfile 按 TARGETARCH 单架构编译 Agent,限制 Node 内存防 OOM
- run.sh 新增 docker fast/upgrade,README 补充 LDAP/AD 与常见问题
This commit is contained in:
Logan committed 2026-07-02 22:45:49 +08:00
1 parent 0f0f2770e1
commit 78c27037e3
12 files changed
+613 -226

No files matched your search

@@ -24,7 +24,10 @@ const SETTINGS_TABS = [
] as const;
type SettingsSubTab = (typeof SETTINGS_TABS)[number]['id'];
export type LdapServerType = 'openldap' | 'ad';
export interface LdapFormData {
server_type: LdapServerType;
ldap_host: string;
ldap_port: number;
use_ldaps: boolean;
@@ -32,6 +35,11 @@ export interface LdapFormData {
admin_password: string;
base_dn: string;
search_filter: string;
user_mapping: {
username: string;
email: string;
display_name: string;
};
}
interface SystemSettingsTabProps {
@@ -325,6 +333,32 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
<div className="space-y-1.5">
<label className="text-xs dg-text-muted">目录类型</label>
<Select
value={ldapForm.server_type}
onValueChange={(v: LdapServerType) => {
const isAD = v === 'ad';
setLdapForm({
...ldapForm,
server_type: v,
ldap_port: isAD && ldapForm.ldap_port === 389 ? 389 : ldapForm.ldap_port,
search_filter: ldapForm.search_filter || (isAD ? '(sAMAccountName=%s)' : '(uid=%s)'),
user_mapping: isAD
? { username: 'sAMAccountName', email: 'mail', display_name: 'displayName' }
: { username: 'uid', email: 'mail', display_name: 'cn' },
});
}}
>
<SelectTrigger className="dg-input">
<SelectValue />
</SelectTrigger>
<SelectContent className="dg-input">
<SelectItem value="openldap">OpenLDAP</SelectItem>
<SelectItem value="ad">Active Directory</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-1.5">
<label className="text-xs dg-text-muted">LDAP 服务器地址</label>
<Input
@@ -350,7 +384,7 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
value={ldapForm.base_dn}
onChange={(e) => setLdapForm({ ...ldapForm, base_dn: e.target.value })}
className="dg-input"
placeholder="ou=users,dc=example,dc=com"
placeholder={ldapForm.server_type === 'ad' ? 'DC=example,DC=com' : 'ou=users,dc=example,dc=com'}
/>
</div>
<div className="space-y-1.5">
@@ -359,7 +393,7 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
value={ldapForm.admin_dn}
onChange={(e) => setLdapForm({ ...ldapForm, admin_dn: e.target.value })}
className="dg-input"
placeholder="cn=admin,dc=example,dc=com"
placeholder={ldapForm.server_type === 'ad' ? 'CN=admin,CN=Users,DC=example,DC=com' : 'cn=admin,dc=example,dc=com'}
/>
</div>
<div className="space-y-1.5">
@@ -378,7 +412,43 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
value={ldapForm.search_filter}
onChange={(e) => setLdapForm({ ...ldapForm, search_filter: e.target.value })}
className="dg-input"
placeholder="(uid=%s)"
placeholder={ldapForm.server_type === 'ad' ? '(sAMAccountName=%s)' : '(uid=%s)'}
/>
</div>
<div className="space-y-1.5">
<label className="text-xs dg-text-muted">用户名字段</label>
<Input
value={ldapForm.user_mapping.username}
onChange={(e) => setLdapForm({
...ldapForm,
user_mapping: { ...ldapForm.user_mapping, username: e.target.value },
})}
className="dg-input"
placeholder={ldapForm.server_type === 'ad' ? 'sAMAccountName' : 'uid'}
/>
</div>
<div className="space-y-1.5">
<label className="text-xs dg-text-muted">邮箱字段</label>
<Input
value={ldapForm.user_mapping.email}
onChange={(e) => setLdapForm({
...ldapForm,
user_mapping: { ...ldapForm.user_mapping, email: e.target.value },
})}
className="dg-input"
placeholder="mail"
/>
</div>
<div className="space-y-1.5">
<label className="text-xs dg-text-muted">显示名字段</label>
<Input
value={ldapForm.user_mapping.display_name}
onChange={(e) => setLdapForm({
...ldapForm,
user_mapping: { ...ldapForm.user_mapping, display_name: e.target.value },
})}
className="dg-input"
placeholder={ldapForm.server_type === 'ad' ? 'displayName' : 'cn'}
/>
</div>
<div className="flex items-center gap-2 col-span-2">
@@ -388,6 +458,9 @@ export function SystemSettingsTab(props: SystemSettingsTabProps) {
className="data-[state=checked]:bg-blue-600"
/>
<span className="text-sm text-[var(--dg-text-secondary)]">启用 LDAPS(SSL 加密)</span>
{ldapForm.server_type === 'ad' && (
<span className="text-xs dg-text-muted">AD 创建用户必须启用 LDAPS</span>
)}
</div>
</div>