"use client" import {useEffect, useMemo, useState} from "react" import {useMutation, useQuery, useQueryClient} from "@tanstack/react-query" import {Fingerprint, Globe, Loader2, Lock, Pencil, Plus, Settings, Trash2, UserPlus} from "lucide-react" import {useRouter} from "next/navigation" import {motion} from "motion/react" import {Button} from "@/components/ui/button" import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card" import {Switch} from "@/components/ui/switch" import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs" import {useAuth} from "@/components/providers/auth-provider" import {AuthSourceModal} from "@/components/common/settings/auth-source-modal" import {AdminService} from "@/lib/services" import type {AuthSource, SystemConfig} from "@/lib/services/admin" import {toast} from "sonner" const SECURITY_KEYS = [ { key: "password_login_enabled", title: "允许密码登录", description: "关闭后仅保留第三方 OIDC 认证源进行系统登录。", icon: Lock, }, { key: "registration_enabled", title: "允许注册", description: "关闭后系统将禁止新用户进行自主账号注册。", icon: UserPlus, }, { key: "password_register_enabled", title: "允许密码注册", description: "关闭后只能通过管理员创建或第三方认证关联建号。", icon: Fingerprint, }, { key: "oidc_login_enabled", title: "允许 OIDC 登录", description: "关闭后所有的第三方 OIDC 认证登录入口都会被隐藏。", icon: Globe, }, ] as const type SecurityKey = (typeof SECURITY_KEYS)[number]["key"] function systemConfigMap(configs: SystemConfig[]) { return configs.reduce>((accumulator, config) => { accumulator[config.key] = config return accumulator }, {}) } export function SecurityMain() { const queryClient = useQueryClient() const { user, loading } = useAuth() const router = useRouter() const [authSourceModalOpen, setAuthSourceModalOpen] = useState(false) const [selectedSource, setSelectedSource] = useState(null) const systemConfigsQuery = useQuery({ queryKey: ["admin", "system-configs"], queryFn: () => AdminService.listSystemConfigs("system"), enabled: !!user?.is_admin, }) const authSourcesQuery = useQuery({ queryKey: ["auth", "sources"], queryFn: () => AdminService.listAuthSources(), enabled: !!user?.is_admin, }) const configs = useMemo( () => systemConfigMap(systemConfigsQuery.data ?? []), [systemConfigsQuery.data], ) useEffect(() => { if (!loading && (!user || !user.is_admin)) { router.replace("/settings/profile") } }, [user, loading, router]) useEffect(() => { if (user?.is_admin) { void systemConfigsQuery.refetch() } }, [systemConfigsQuery, user]) const updateConfigMutation = useMutation({ mutationFn: async ({ key, value }: { key: SecurityKey; value: boolean }) => { const config = configs[key] if (!config) { throw new Error(`缺少配置项: ${key}`) } await AdminService.updateSystemConfig(key, { value: value ? "true" : "false", description: config.description, }) }, onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["admin", "system-configs"] }) toast.success("系统安全配置已更新") }, onError: (error: Error) => { toast.error(error.message || "更新配置失败") }, }) const toggleSourceMutation = useMutation({ mutationFn: async (source: AuthSource) => { await AdminService.toggleAuthSource(source.id, { is_active: !source.is_active }) }, onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["auth", "sources"] }) await queryClient.invalidateQueries({ queryKey: ["auth", "public-sources"] }) toast.success("认证源状态已更新") }, onError: (error: Error) => { toast.error(error.message || "切换状态失败") }, }) const deleteSourceMutation = useMutation({ mutationFn: async (sourceId: string) => { await AdminService.deleteAuthSource(sourceId) }, onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["auth", "sources"] }) await queryClient.invalidateQueries({ queryKey: ["auth", "public-sources"] }) toast.success("认证源已删除") }, onError: (error: Error) => { toast.error(error.message || "删除认证源失败") }, }) const handleToggle = (key: SecurityKey, checked: boolean) => { updateConfigMutation.mutate({ key, value: checked }) } if (loading || !user || !user.is_admin) { return (
) } return ( 系统安全设置 运营设置 系统设置 其他设置 系统信息
{/* 系统登录与注册控制 */}
系统安全与注册控制 配置系统的登录限制与用户自主注册权限
{SECURITY_KEYS.map((item) => { const config = configs[item.key] const checked = config ? config.value === "true" : false const Icon = item.icon return (
{Icon && } {item.title}

{item.description}

handleToggle(item.key, value)} />
) })}
{/* 认证源配置管理 */}
认证源管理 添加、修改并启用系统自定义的 OIDC 认证源
{authSourcesQuery.isPending ? (
) : (authSourcesQuery.data ?? []).length > 0 ? ( (authSourcesQuery.data ?? []).map((source) => (
{source.display_name || source.name} {source.is_active ? "已启用" : "已禁用"}
标识符: {source.name} · 类型: {source.type.toUpperCase()}
toggleSourceMutation.mutate(source)} />
)) ) : (
暂无配置的认证源,点击上方按钮新增
)}
setAuthSourceModalOpen(false)} onChanged={async () => { await queryClient.invalidateQueries({ queryKey: ["auth", "sources"] }) await queryClient.invalidateQueries({ queryKey: ["auth", "public-sources"] }) await authSourcesQuery.refetch() }} />
) }