refactor: Simplify user authorization component and improve error handling

This commit is contained in:
wood chen 2025-02-21 18:32:59 +08:00
parent 2f848af557
commit 1b4a988ba2
4 changed files with 37 additions and 81 deletions

View File

@ -26,7 +26,7 @@ export async function signIn(data: Record<string, any>) {
const state = params.get("state"); const state = params.get("state");
const scope = params.get("scope") || "read_profile"; const scope = params.get("scope") || "read_profile";
// 重新构建授权页面 URL,使用相对路径 // 重新构建授权页面 URL
const authParams = new URLSearchParams({ const authParams = new URLSearchParams({
response_type: "code", response_type: "code",
client_id: clientId || "", client_id: clientId || "",
@ -37,16 +37,14 @@ export async function signIn(data: Record<string, any>) {
authParams.set("state", state); authParams.set("state", state);
} }
// 重定向到授权页面,使用相对路径 // 重定向到 OAuth 授权页面
redirect(`/oauth/authorize?${authParams.toString()}`); redirect(`/oauth/authorize?${authParams.toString()}`);
return;
} }
// 如果没有 OAuth 参数,重定向到仪表板 // 如果没有 OAuth 参数,重定向到仪表板
redirect("/dashboard"); redirect("/dashboard");
} catch (error) { } catch (error) {
console.error("登录失败:", error); console.error("登录失败:", error);
// 添加时间戳防止循环 throw error;
redirect(`/sign-in?error=AuthenticationError&t=${Date.now()}`);
} }
} }

View File

@ -0,0 +1,27 @@
import { redirect } from "next/navigation";
import { signIn } from "@/actions/user-authorize";
interface CallbackParams {
sso: string;
sig: string;
}
export default async function AuthorizeCallbackPage({
searchParams,
}: {
searchParams: CallbackParams;
}) {
const { sso, sig } = searchParams;
if (!sso || !sig) {
redirect("/sign-in?error=InvalidCallback");
}
try {
// 进行 SSO 登录
await signIn({ sso, sig });
} catch (error) {
console.error("登录失败:", error);
redirect("/sign-in?error=AuthenticationError");
}
}

View File

@ -17,8 +17,10 @@ export async function POST(req: Request) {
const body = await req.json().catch(() => ({})); const body = await req.json().catch(() => ({}));
const oauthParams = body.oauth_params || ""; const oauthParams = body.oauth_params || "";
// 设置回调地址,如果有 OAuth 参数则保存 // 设置回调地址
const return_url = `${hostUrl}/authorize`; const return_url = `${hostUrl}/authorize/callback`;
// 如果有 OAuth 参数,保存到 cookie
if (oauthParams) { if (oauthParams) {
cookies().set("oauth_params", oauthParams, { cookies().set("oauth_params", oauthParams, {
maxAge: 60 * 10, // 10分钟过期 maxAge: 60 * 10, // 10分钟过期

View File

@ -1,8 +1,6 @@
"use client"; "use client";
import { useCallback, useEffect, useState } from "react"; import { useRouter } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import { signIn } from "@/actions/user-authorize";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@ -15,86 +13,17 @@ export function UserAuthorize({
data, data,
...props ...props
}: UserAuthorizeProps) { }: UserAuthorizeProps) {
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<Error | unknown>(null);
const router = useRouter();
const searchParams = useSearchParams();
// 检查是否是 OAuth 授权页面
const isOAuthFlow =
searchParams?.has("client_id") && searchParams?.has("redirect_uri");
// 检查是否是 SSO 回调
const isSSOCallback = searchParams?.has("sso") && searchParams?.has("sig");
const signInCallback = useCallback(async () => {
if (isLoading || !isSSOCallback || isOAuthFlow) {
return;
}
setIsLoading(true);
try {
const sso = searchParams?.get("sso");
const sig = searchParams?.get("sig");
// 传递 SSO 参数
await signIn({
sso,
sig,
});
// 登录成功后刷新路由状态
router.refresh();
} catch (error) {
console.error("登录过程出错:", error);
setError(error);
} finally {
setIsLoading(false);
}
}, [isLoading, isSSOCallback, isOAuthFlow, router, searchParams]);
useEffect(() => {
signInCallback();
}, [signInCallback]);
if (error) {
return (
<Card className="w-full">
<CardHeader className="space-y-4 text-center">
<div className="mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-red-100">
<div className="h-8 w-8 text-red-600"></div>
</div>
<CardTitle className="text-2xl font-semibold text-red-600">
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-center text-gray-500">
{error instanceof Error
? error.message
: "登录异常,授权失败!请稍后重试。"}
</p>
</CardContent>
</Card>
);
}
return ( return (
<Card className="w-full"> <Card className="w-full">
<CardHeader className="space-y-4 text-center"> <CardHeader className="space-y-4 text-center">
<div className="mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-blue-100"> <div className="mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-blue-100">
<div className="h-8 w-8 animate-spin rounded-full border-4 border-blue-600 border-t-transparent"></div> <div className="h-8 w-8 animate-spin rounded-full border-4 border-blue-600 border-t-transparent"></div>
</div> </div>
<CardTitle className="text-2xl font-semibold"> <CardTitle className="text-2xl font-semibold"></CardTitle>
{isOAuthFlow ? "正在处理授权" : "正在处理登录"}
</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<p className="text-center text-gray-500"> <p className="text-center text-gray-500">
{isOAuthFlow
? "请稍候,我们正在处理您的授权请求"
: isLoading
? "请稍候,我们正在处理您的登录请求"
: "正在跳转..."}
</p> </p>
</CardContent> </CardContent>
</Card> </Card>