From 4cc43836039620938eefa8237497c74db4551844 Mon Sep 17 00:00:00 2001 From: zetaloop Date: Fri, 20 Feb 2026 22:38:29 +0800 Subject: [PATCH] feat: add auth guards to protected routes and extend requireAuth coverage --- app/(account)/layout.tsx | 5 ++++- app/(dashboard)/layout.tsx | 5 ++++- app/(main)/post/new/page.tsx | 7 +++++++ app/(order)/layout.tsx | 14 +++++++++++++- app/(order)/order/new/page.tsx | 4 +++- components/auth-guard.tsx | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 components/auth-guard.tsx diff --git a/app/(account)/layout.tsx b/app/(account)/layout.tsx index 551e477..e9eceb6 100644 --- a/app/(account)/layout.tsx +++ b/app/(account)/layout.tsx @@ -1,4 +1,5 @@ import { AccountSidebar } from "@/components/account-sidebar" +import { AuthGuard } from "@/components/auth-guard" import { Header } from "@/components/header" export default function AccountLayout({ children }: { children: React.ReactNode }) { @@ -9,7 +10,9 @@ export default function AccountLayout({ children }: { children: React.ReactNode
-
{children}
+
+ {children} +
) diff --git a/app/(dashboard)/layout.tsx b/app/(dashboard)/layout.tsx index 5bacc59..e4bd69f 100644 --- a/app/(dashboard)/layout.tsx +++ b/app/(dashboard)/layout.tsx @@ -1,3 +1,4 @@ +import { AuthGuard } from "@/components/auth-guard" import { DashboardSidebar } from "@/components/dashboard-sidebar" import { Header } from "@/components/header" @@ -9,7 +10,9 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
-
{children}
+
+ {children} +
) diff --git a/app/(main)/post/new/page.tsx b/app/(main)/post/new/page.tsx index a818b22..c9a8e50 100644 --- a/app/(main)/post/new/page.tsx +++ b/app/(main)/post/new/page.tsx @@ -20,6 +20,7 @@ import { SelectValue, } from "@/components/ui/select" import { Textarea } from "@/components/ui/textarea" +import { useRequireAuth } from "@/lib/use-require-auth" const postSchema = z.object({ title: z.string().min(2, "标题至少2个字符").max(50, "标题最多50个字符"), @@ -30,6 +31,7 @@ const tagOptions = ["英雄联盟", "王者荣耀", "CS2", "原神", "上分", " export default function NewPostPage() { const router = useRouter() + const { isAuthenticated, requireAuth } = useRequireAuth() const [postType, setPostType] = useState("normal") const [selectedTags, setSelectedTags] = useState([]) const [imageCount, setImageCount] = useState(0) @@ -49,6 +51,11 @@ export default function NewPostPage() { } const onSubmit = async () => { + if (!isAuthenticated) { + requireAuth(() => undefined) + return + } + await new Promise((r) => setTimeout(r, 500)) router.push("/community") } diff --git a/app/(order)/layout.tsx b/app/(order)/layout.tsx index a26f97c..f7f230f 100644 --- a/app/(order)/layout.tsx +++ b/app/(order)/layout.tsx @@ -1,10 +1,22 @@ +"use client" + +import { usePathname } from "next/navigation" +import { AuthGuard } from "@/components/auth-guard" import { Header } from "@/components/header" export default function OrderLayout({ children }: { children: React.ReactNode }) { + const pathname = usePathname() + const protectedPathPrefixes = ["/orders", "/order", "/chat", "/dispute", "/review"] + const shouldGuard = protectedPathPrefixes.some( + (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`), + ) + return (
-
{children}
+
+ {shouldGuard ? {children} : children} +
) } diff --git a/app/(order)/order/new/page.tsx b/app/(order)/order/new/page.tsx index 8144c04..9534859 100644 --- a/app/(order)/order/new/page.tsx +++ b/app/(order)/order/new/page.tsx @@ -12,9 +12,11 @@ import { Label } from "@/components/ui/label" import { Separator } from "@/components/ui/separator" import { Textarea } from "@/components/ui/textarea" import { mockPlayers, mockServices, walletBalance } from "@/lib/mock-data" +import { useRequireAuth } from "@/lib/use-require-auth" export default function NewOrderPage() { const searchParams = useSearchParams() + const { requireAuth } = useRequireAuth() const serviceId = searchParams.get("serviceId") const service = mockServices.find((s) => s.id === serviceId) @@ -168,7 +170,7 @@ export default function NewOrderPage() { className="w-full" size="lg" disabled={walletBalance < totalPrice} - onClick={() => setSubmitted(true)} + onClick={() => requireAuth(() => setSubmitted(true))} > 确认支付 ¥{totalPrice} diff --git a/components/auth-guard.tsx b/components/auth-guard.tsx new file mode 100644 index 0000000..bca9f4f --- /dev/null +++ b/components/auth-guard.tsx @@ -0,0 +1,32 @@ +"use client" + +import { useEffect } from "react" +import { Button } from "@/components/ui/button" +import { useAuthStore } from "@/store/auth" +import { useLoginDialogStore } from "@/store/login-dialog" + +interface AuthGuardProps { + children: React.ReactNode +} + +export function AuthGuard({ children }: AuthGuardProps) { + const isAuthenticated = useAuthStore((s) => s.isAuthenticated) + const openLoginDialog = useLoginDialogStore((s) => s.openLoginDialog) + + useEffect(() => { + if (!isAuthenticated) { + openLoginDialog() + } + }, [isAuthenticated, openLoginDialog]) + + if (isAuthenticated) { + return <>{children} + } + + return ( +
+

请先登录后继续访问此页面

+ +
+ ) +}