From ed1d420ce90ab943f4c44a34f1f95e1d32a75773 Mon Sep 17 00:00:00 2001 From: longsizhuo Date: Wed, 25 Mar 2026 02:37:06 +0800 Subject: [PATCH 01/16] =?UTF-8?q?feat:=20=E4=B8=BA=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E7=9A=84=E5=AD=98=E5=9C=A8=E5=81=9A=E5=87=86=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/auth/[...nextauth]/route.ts | 2 - app/api/upload/route.ts | 19 +++-- app/components/AuthNav.tsx | 20 ++--- app/components/Header.tsx | 21 ++--- app/components/SignInButton.tsx | 15 ++-- app/components/UmamiIdentity.tsx | 14 ++-- app/components/UserMenu.tsx | 7 +- app/editor/EditorPageClient.tsx | 12 +-- app/editor/page.tsx | 38 ++++++--- app/layout.tsx | 6 +- app/login/page.tsx | 8 +- auth.config.ts | 75 ----------------- auth.ts | 51 ------------ lib/use-auth.tsx | 120 ++++++++++++++++++++++++++++ next.config.mjs | 10 +++ proxy.ts | 10 --- 16 files changed, 217 insertions(+), 211 deletions(-) delete mode 100644 app/api/auth/[...nextauth]/route.ts delete mode 100644 auth.config.ts delete mode 100644 auth.ts create mode 100644 lib/use-auth.tsx delete mode 100644 proxy.ts diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts deleted file mode 100644 index 7c62e2db..00000000 --- a/app/api/auth/[...nextauth]/route.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { handlers } from "@/auth"; -export const { GET, POST } = handlers; diff --git a/app/api/upload/route.ts b/app/api/upload/route.ts index f0e74c52..a35eed36 100644 --- a/app/api/upload/route.ts +++ b/app/api/upload/route.ts @@ -1,5 +1,5 @@ -import { auth } from "@/auth"; import { NextRequest, NextResponse } from "next/server"; +import type { UserView } from "@/lib/use-auth"; import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import { sanitizeDocumentSlug, sanitizeResourceKey } from "@/lib/sanitizer"; @@ -36,12 +36,21 @@ interface UploadRequest { */ export async function POST(request: NextRequest) { try { - // 验证用户身份 - const session = await auth(); + // 从请求头读取 satoken,转发给后端验证 + const token = request.headers.get("satoken"); + if (!token) { + return NextResponse.json({ error: "未授权访问" }, { status: 401 }); + } - if (!session?.user?.id) { + // 调用后端 /api/v1/auth/me 验证 token 并获取用户信息 + const meRes = await fetch("http://localhost:8080/api/v1/auth/me", { + headers: { satoken: token }, + }); + if (!meRes.ok) { return NextResponse.json({ error: "未授权访问" }, { status: 401 }); } + const meBody = (await meRes.json()) as { data: UserView }; + const currentUser = meBody.data; // 验证环境变量 if ( @@ -81,7 +90,7 @@ export async function POST(request: NextRequest) { // 生成唯一的对象键 // 格式:users/{userId}/{article-slug}/{timestamp}-{filename} const timestamp = Date.now(); - const userId = session.user.id; + const userId = String(currentUser.id); const sanitizedSlug = sanitizeDocumentSlug(articleSlug); const sanitizedFilename = sanitizeResourceKey(filename); const key = `users/${userId}/${sanitizedSlug}/${timestamp}-${sanitizedFilename}`; diff --git a/app/components/AuthNav.tsx b/app/components/AuthNav.tsx index e258007f..76cee798 100644 --- a/app/components/AuthNav.tsx +++ b/app/components/AuthNav.tsx @@ -1,21 +1,23 @@ "use client"; -import { useSession } from "next-auth/react"; +import { useAuth } from "@/lib/use-auth"; import { SignInButton } from "@/app/components/SignInButton"; import { UserMenu } from "@/app/components/UserMenu"; export function AuthNav() { - const { data: session, status } = useSession(); + const { user, status, logout } = useAuth(); if (status === "loading") { return
; } - const user = session?.user; - const provider = - session && "provider" in session - ? (session.provider as string | undefined) - : undefined; - - return user ? : ; + return user ? ( + + ) : ( + + ); } diff --git a/app/components/Header.tsx b/app/components/Header.tsx index 8bb7cd8d..695895f6 100644 --- a/app/components/Header.tsx +++ b/app/components/Header.tsx @@ -2,19 +2,12 @@ import { ThemeToggle } from "./ThemeToggle"; import { Button } from "@/components/ui/button"; import { MessageCircle } from "lucide-react"; import { Github as GithubIcon } from "./icons/Github"; -import { SignInButton } from "./SignInButton"; -import { auth } from "@/auth"; -import { UserMenu } from "./UserMenu"; +import { AuthNav } from "./AuthNav"; import { BrandMark } from "./BrandMark"; import { LiveEditionLabel } from "./LiveEditionLabel"; -export async function Header() { - const session = await auth(); - const user = session?.user; - const provider = - session && "provider" in session - ? (session.provider as string | undefined) - : undefined; +// 改为普通服务端组件,登录状态由客户端 AuthNav 处理 +export function Header() { const now = new Date(); const editionTimestampMs = now.getTime(); const formattedDate = now.toLocaleDateString("en-US", { @@ -22,7 +15,6 @@ export async function Header() { day: "numeric", year: "numeric", }); - console.log("session", session); return (
@@ -103,11 +95,8 @@ export async function Header() { - {user ? ( - - ) : ( - - )} + {/* AuthNav 是客户端组件,内部通过 useAuth() 自动处理登录/未登录状态 */} +
diff --git a/app/components/SignInButton.tsx b/app/components/SignInButton.tsx index a1afef51..e7b7a669 100644 --- a/app/components/SignInButton.tsx +++ b/app/components/SignInButton.tsx @@ -1,24 +1,21 @@ "use client"; -import { signIn } from "next-auth/react"; import { Button } from "@/app/components/ui/button"; interface SignInButtonProps { className?: string; - redirectTo?: string; - /** - * @deprecated Use `redirectTo` (NextAuth v5). Kept for backward compatibility. - */ - callbackUrl?: string; } -export function SignInButton({ className, redirectTo }: SignInButtonProps) { - const targetUrl = redirectTo ?? "/"; +export function SignInButton({ className }: SignInButtonProps) { + // 跳转到后端 GitHub OAuth 入口,后端完成授权后会带着 token 重定向回前端首页 + const handleSignIn = () => { + window.location.href = "/api/v1/oauth/render/github"; + }; return (