From c51d4869ba39d61aa7f22b12ee91be558dd45eaf Mon Sep 17 00:00:00 2001 From: wood chen Date: Sun, 16 Feb 2025 14:06:04 +0800 Subject: [PATCH] feat(auth): Add authentication to cache management API and frontend - Implement token-based authentication for cache-related API endpoints - Add authorization headers to frontend fetch requests - Handle unauthorized access by redirecting to login page - Improve security for cache configuration and management routes --- main.go | 8 +++ web/app/dashboard/cache/page.tsx | 95 +++++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index f875c39..29f2e7d 100644 --- a/main.go +++ b/main.go @@ -87,6 +87,14 @@ func main() { proxyHandler.AuthMiddleware(handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache, fixedPathCache).SetCacheEnabled)(w, r) case "/admin/api/cache/clear": proxyHandler.AuthMiddleware(handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache, fixedPathCache).ClearCache)(w, r) + case "/admin/api/cache/config": + if r.Method == http.MethodGet { + proxyHandler.AuthMiddleware(handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache, fixedPathCache).GetCacheConfig)(w, r) + } else if r.Method == http.MethodPost { + proxyHandler.AuthMiddleware(handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache, fixedPathCache).UpdateCacheConfig)(w, r) + } else { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + } default: http.NotFound(w, r) } diff --git a/web/app/dashboard/cache/page.tsx b/web/app/dashboard/cache/page.tsx index f881740..137ef30 100644 --- a/web/app/dashboard/cache/page.tsx +++ b/web/app/dashboard/cache/page.tsx @@ -7,6 +7,7 @@ import { useToast } from "@/components/ui/use-toast" import { Switch } from "@/components/ui/switch" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" +import { useRouter } from "next/navigation" interface CacheStats { total_items: number @@ -54,10 +55,28 @@ export default function CachePage() { const [configs, setConfigs] = useState(null) const [loading, setLoading] = useState(true) const { toast } = useToast() + const router = useRouter() const fetchStats = useCallback(async () => { try { - const response = await fetch("/admin/api/cache/stats") + const token = localStorage.getItem("token") + if (!token) { + router.push("/login") + return + } + + const response = await fetch("/admin/api/cache/stats", { + headers: { + 'Authorization': `Bearer ${token}` + } + }) + + if (response.status === 401) { + localStorage.removeItem("token") + router.push("/login") + return + } + if (!response.ok) throw new Error("获取缓存统计失败") const data = await response.json() setStats(data) @@ -70,11 +89,28 @@ export default function CachePage() { } finally { setLoading(false) } - }, [toast]) + }, [toast, router]) const fetchConfigs = useCallback(async () => { try { - const response = await fetch("/admin/api/cache/config") + const token = localStorage.getItem("token") + if (!token) { + router.push("/login") + return + } + + const response = await fetch("/admin/api/cache/config", { + headers: { + 'Authorization': `Bearer ${token}` + } + }) + + if (response.status === 401) { + localStorage.removeItem("token") + router.push("/login") + return + } + if (!response.ok) throw new Error("获取缓存配置失败") const data = await response.json() setConfigs(data) @@ -85,7 +121,7 @@ export default function CachePage() { variant: "destructive", }) } - }, [toast]) + }, [toast, router]) useEffect(() => { // 立即获取一次数据 @@ -99,12 +135,27 @@ export default function CachePage() { const handleToggleCache = async (type: "proxy" | "mirror" | "fixedPath", enabled: boolean) => { try { + const token = localStorage.getItem("token") + if (!token) { + router.push("/login") + return + } + const response = await fetch("/admin/api/cache/enable", { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + 'Authorization': `Bearer ${token}` + }, body: JSON.stringify({ type, enabled }), }) + if (response.status === 401) { + localStorage.removeItem("token") + router.push("/login") + return + } + if (!response.ok) throw new Error("切换缓存状态失败") toast({ @@ -124,12 +175,27 @@ export default function CachePage() { const handleUpdateConfig = async (type: "proxy" | "mirror" | "fixedPath", config: CacheConfig) => { try { + const token = localStorage.getItem("token") + if (!token) { + router.push("/login") + return + } + const response = await fetch("/admin/api/cache/config", { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + 'Authorization': `Bearer ${token}` + }, body: JSON.stringify({ type, config }), }) + if (response.status === 401) { + localStorage.removeItem("token") + router.push("/login") + return + } + if (!response.ok) throw new Error("更新缓存配置失败") toast({ @@ -149,12 +215,27 @@ export default function CachePage() { const handleClearCache = async (type: "proxy" | "mirror" | "fixedPath" | "all") => { try { + const token = localStorage.getItem("token") + if (!token) { + router.push("/login") + return + } + const response = await fetch("/admin/api/cache/clear", { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + 'Authorization': `Bearer ${token}` + }, body: JSON.stringify({ type }), }) + if (response.status === 401) { + localStorage.removeItem("token") + router.push("/login") + return + } + if (!response.ok) throw new Error("清理缓存失败") toast({