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
This commit is contained in:
wood chen 2025-02-16 14:06:04 +08:00
parent 8a910d9d91
commit c51d4869ba
2 changed files with 96 additions and 7 deletions

View File

@ -87,6 +87,14 @@ func main() {
proxyHandler.AuthMiddleware(handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache, fixedPathCache).SetCacheEnabled)(w, r) proxyHandler.AuthMiddleware(handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache, fixedPathCache).SetCacheEnabled)(w, r)
case "/admin/api/cache/clear": case "/admin/api/cache/clear":
proxyHandler.AuthMiddleware(handler.NewCacheAdminHandler(proxyHandler.Cache, mirrorHandler.Cache, fixedPathCache).ClearCache)(w, r) 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: default:
http.NotFound(w, r) http.NotFound(w, r)
} }

View File

@ -7,6 +7,7 @@ import { useToast } from "@/components/ui/use-toast"
import { Switch } from "@/components/ui/switch" import { Switch } from "@/components/ui/switch"
import { Input } from "@/components/ui/input" import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label" import { Label } from "@/components/ui/label"
import { useRouter } from "next/navigation"
interface CacheStats { interface CacheStats {
total_items: number total_items: number
@ -54,10 +55,28 @@ export default function CachePage() {
const [configs, setConfigs] = useState<CacheConfigs | null>(null) const [configs, setConfigs] = useState<CacheConfigs | null>(null)
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const { toast } = useToast() const { toast } = useToast()
const router = useRouter()
const fetchStats = useCallback(async () => { const fetchStats = useCallback(async () => {
try { 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("获取缓存统计失败") if (!response.ok) throw new Error("获取缓存统计失败")
const data = await response.json() const data = await response.json()
setStats(data) setStats(data)
@ -70,11 +89,28 @@ export default function CachePage() {
} finally { } finally {
setLoading(false) setLoading(false)
} }
}, [toast]) }, [toast, router])
const fetchConfigs = useCallback(async () => { const fetchConfigs = useCallback(async () => {
try { 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("获取缓存配置失败") if (!response.ok) throw new Error("获取缓存配置失败")
const data = await response.json() const data = await response.json()
setConfigs(data) setConfigs(data)
@ -85,7 +121,7 @@ export default function CachePage() {
variant: "destructive", variant: "destructive",
}) })
} }
}, [toast]) }, [toast, router])
useEffect(() => { useEffect(() => {
// 立即获取一次数据 // 立即获取一次数据
@ -99,12 +135,27 @@ export default function CachePage() {
const handleToggleCache = async (type: "proxy" | "mirror" | "fixedPath", enabled: boolean) => { const handleToggleCache = async (type: "proxy" | "mirror" | "fixedPath", enabled: boolean) => {
try { try {
const token = localStorage.getItem("token")
if (!token) {
router.push("/login")
return
}
const response = await fetch("/admin/api/cache/enable", { const response = await fetch("/admin/api/cache/enable", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ type, enabled }), body: JSON.stringify({ type, enabled }),
}) })
if (response.status === 401) {
localStorage.removeItem("token")
router.push("/login")
return
}
if (!response.ok) throw new Error("切换缓存状态失败") if (!response.ok) throw new Error("切换缓存状态失败")
toast({ toast({
@ -124,12 +175,27 @@ export default function CachePage() {
const handleUpdateConfig = async (type: "proxy" | "mirror" | "fixedPath", config: CacheConfig) => { const handleUpdateConfig = async (type: "proxy" | "mirror" | "fixedPath", config: CacheConfig) => {
try { try {
const token = localStorage.getItem("token")
if (!token) {
router.push("/login")
return
}
const response = await fetch("/admin/api/cache/config", { const response = await fetch("/admin/api/cache/config", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ type, config }), body: JSON.stringify({ type, config }),
}) })
if (response.status === 401) {
localStorage.removeItem("token")
router.push("/login")
return
}
if (!response.ok) throw new Error("更新缓存配置失败") if (!response.ok) throw new Error("更新缓存配置失败")
toast({ toast({
@ -149,12 +215,27 @@ export default function CachePage() {
const handleClearCache = async (type: "proxy" | "mirror" | "fixedPath" | "all") => { const handleClearCache = async (type: "proxy" | "mirror" | "fixedPath" | "all") => {
try { try {
const token = localStorage.getItem("token")
if (!token) {
router.push("/login")
return
}
const response = await fetch("/admin/api/cache/clear", { const response = await fetch("/admin/api/cache/clear", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ type }), body: JSON.stringify({ type }),
}) })
if (response.status === 401) {
localStorage.removeItem("token")
router.push("/login")
return
}
if (!response.ok) throw new Error("清理缓存失败") if (!response.ok) throw new Error("清理缓存失败")
toast({ toast({