From 80e281f9862ff4cc9739b2bb4b67a9b054667f0b Mon Sep 17 00:00:00 2001 From: wood chen Date: Fri, 21 Feb 2025 21:49:44 +0800 Subject: [PATCH] refactor: Streamline OAuth and SSO authentication flow across multiple components --- src/app/(auth)/authorize/page.tsx | 22 +++++--------- src/app/(oauth)/oauth/authorize/page.tsx | 13 +++----- src/app/api/auth/q58/route.ts | 27 ++++++++++++++--- src/components/auth/user-auth-form.tsx | 38 +++++++----------------- 4 files changed, 44 insertions(+), 56 deletions(-) diff --git a/src/app/(auth)/authorize/page.tsx b/src/app/(auth)/authorize/page.tsx index 605d7df..1e839b2 100644 --- a/src/app/(auth)/authorize/page.tsx +++ b/src/app/(auth)/authorize/page.tsx @@ -5,22 +5,17 @@ import Link from "next/link"; import { useRouter, useSearchParams } from "next/navigation"; import { MessageCircleCode } from "lucide-react"; -import { UserAuthorize } from "@/components/auth/user-authorize"; - -type Props = { - searchParams: { [key: string]: string | string[] | undefined }; -}; - -export default function AuthPage({ searchParams }: Props) { +export default function AuthPage() { const router = useRouter(); - const urlSearchParams = useSearchParams(); - const callbackUrl = urlSearchParams.get("callbackUrl"); + const searchParams = useSearchParams(); useEffect(() => { - if (callbackUrl) { - router.replace(callbackUrl); + // 如果有 OAuth 参数,重定向回 /oauth/authorize + if (searchParams.has("response_type") && searchParams.has("client_id")) { + router.replace(`/oauth/authorize?${searchParams.toString()}`); + return; } - }, [callbackUrl, router]); + }, [router, searchParams]); return (
@@ -31,9 +26,6 @@ export default function AuthPage({ searchParams }: Props) { Q58论坛
-
- -

By clicking continue, you agree to our{" "} { - if (value) currentUrl.searchParams.append(key, value.toString()); + if (value) params.append(key, value); }); - redirect( - `/sign-in?callbackUrl=${encodeURIComponent(currentUrl.toString())}`, - ); + redirect(`/sign-in?${params.toString()}`); } // 验证必要的参数 diff --git a/src/app/api/auth/q58/route.ts b/src/app/api/auth/q58/route.ts index 2bd2a10..8773dac 100644 --- a/src/app/api/auth/q58/route.ts +++ b/src/app/api/auth/q58/route.ts @@ -10,22 +10,31 @@ const discourseHost = process.env.DISCOURSE_HOST as string; const clientSecret = process.env.DISCOURSE_SECRET as string; export async function POST(req: Request) { + console.log("开始处理 SSO 登录请求..."); + try { const nonce = WordArray.random(16).toString(); let return_url = `${hostUrl}/authorize`; try { const body = await req.json(); + console.log("收到请求体:", body); + if (body.return_url) { - return_url = body.return_url; + return_url = `${hostUrl}${body.return_url}`; + console.log("使用自定义 return_url:", return_url); + } else { + console.log("使用默认 return_url:", return_url); } } catch (error) { - console.error("Failed to parse request body:", error); + console.error("解析请求体失败:", error); } + console.log("生成 SSO 参数..."); const sso = btoa(`nonce=${nonce}&return_sso_url=${return_url}`); const sig = hmacSHA256(sso, clientSecret).toString(Hex); + console.log("设置 nonce cookie..."); cookies().set(AUTH_NONCE, nonce, { maxAge: 60 * 10, path: "/", @@ -33,11 +42,21 @@ export async function POST(req: Request) { secure: process.env.NODE_ENV === "production", }); + const sso_url = `${discourseHost}/session/sso_provider?sso=${sso}&sig=${sig}`; + console.log("生成 SSO URL:", sso_url); + return Response.json({ - sso_url: `${discourseHost}/session/sso_provider?sso=${sso}&sig=${sig}`, + sso_url: sso_url, }); } catch (error) { console.error("SSO 处理错误:", error); - return Response.json({ error: "处理登录请求时发生错误" }, { status: 500 }); + const errorMessage = error instanceof Error ? error.message : String(error); + return Response.json( + { + error: "处理登录请求时发生错误", + details: errorMessage, + }, + { status: 500 }, + ); } } diff --git a/src/components/auth/user-auth-form.tsx b/src/components/auth/user-auth-form.tsx index 234d605..4522c37 100644 --- a/src/components/auth/user-auth-form.tsx +++ b/src/components/auth/user-auth-form.tsx @@ -24,30 +24,14 @@ export function UserAuthForm({ async function signIn() { try { const body: Record = {}; - const callbackUrl = searchParams?.get("callbackUrl"); - console.log("Original callbackUrl:", callbackUrl); - - // 如果是 OAuth 回调,则保留完整的 OAuth 参数 - if (callbackUrl?.includes("/oauth/authorize")) { - try { - // 先解码一次 URL - const decodedUrl = decodeURIComponent(callbackUrl); - console.log("Decoded URL:", decodedUrl); - - // 解析 URL 并保留所有参数 - const url = new URL(decodedUrl); - if (url.pathname === "/oauth/authorize") { - body.return_url = `${window.location.origin}${url.pathname}${url.search}`; - console.log("Extracted return_url:", body.return_url); - } - } catch (e) { - console.error("URL 处理错误:", e); - body.return_url = `${window.location.origin}/authorize`; - } + // 如果有 OAuth 参数,作为 return_url 传递 + if (searchParams.has("response_type") && searchParams.has("client_id")) { + body.return_url = `/oauth/authorize?${searchParams.toString()}`; + console.log("正在处理 OAuth 登录,return_url:", body.return_url); } - console.log("发送请求体:", body); + console.log("发送登录请求..."); const response = await fetch("/api/auth/q58", { method: "POST", headers: { @@ -57,20 +41,18 @@ export function UserAuthForm({ }); if (!response.ok) { - const errorText = await response.text(); - console.error("服务器响应:", errorText); - throw new Error(`登录请求失败: ${errorText}`); + const errorData = await response.text(); + console.error("登录请求失败:", errorData); + throw new Error(`登录请求失败: ${errorData}`); } const data = await response.json(); - console.log("收到 SSO URL:", data.sso_url); - - // 直接使用 window.location.href 跳转 + console.log("获取到 SSO URL:", data.sso_url); window.location.href = data.sso_url; } catch (error) { console.error("登录错误:", error); toast({ - title: "错误", + title: "登录失败", description: error instanceof Error ? error.message