refactor: 改进 OAuth 参数处理和错误处理机制

This commit is contained in:
wood chen 2025-02-21 17:54:17 +08:00
parent 1c0aa7e65f
commit e193568ee8
3 changed files with 59 additions and 30 deletions

View File

@ -14,17 +14,23 @@ export async function signIn(data: Record<string, any>) {
const params = new URLSearchParams(atob(sso));
const returnSsoUrl = params.get("return_sso_url");
if (returnSsoUrl) {
// 解析 return_sso_url 中的参数
const returnUrl = new URL(returnSsoUrl);
const hasOAuthParams = returnUrl.searchParams.has("client_id");
if (hasOAuthParams) {
// 如果 URL 中包含 OAuth 参数,直接重定向(此时应该是 /authorize 页面)
redirect(returnSsoUrl);
}
if (!returnSsoUrl) {
redirect("/dashboard");
}
// 如果没有有效的重定向 URL默认到仪表板
// 检查是否是 OAuth 流程
try {
const returnUrl = new URL(returnSsoUrl);
const isOAuthFlow = returnUrl.pathname.startsWith("/oauth/authorize");
if (isOAuthFlow) {
// 如果是 OAuth 流程,继续授权流程
redirect(returnSsoUrl);
}
} catch (error) {
console.error("Invalid return URL:", error);
}
// 默认重定向到仪表板
redirect("/dashboard");
}

View File

@ -11,22 +11,27 @@ const clientSecret = process.env.DISCOURSE_SECRET as string;
export async function POST(req: Request) {
const nonce = WordArray.random(16).toString();
const referer = headers().get("referer") || "";
const url = new URL(referer);
const searchParams = url.searchParams.toString();
// 保存原始的 OAuth 参数到 cookie用于后续重定向
if (searchParams) {
cookies().set("oauth_params", searchParams, {
maxAge: 60 * 10, // 10分钟过期
path: "/",
});
// 尝试从请求体中获取 OAuth 参数
let oauthParams = "";
try {
const body = await req.json();
if (body.oauth_params) {
oauthParams = body.oauth_params;
// 保存 OAuth 参数到 cookie
cookies().set("oauth_params", oauthParams, {
maxAge: 60 * 10, // 10分钟过期
path: "/",
});
}
} catch (error) {
console.error("Failed to parse request body:", error);
}
// 设置 SSO 回调地址,将 OAuth 参数编码后传递
const return_url = searchParams
? `${hostUrl}/authorize?${searchParams}` // 直接将 OAuth 参数附加到回调 URL
: `${hostUrl}/dashboard`; // 如果没有 OAuth 参数,回到仪表板
// 设置回调地址
const return_url = oauthParams
? `${hostUrl}/authorize?${oauthParams}` // OAuth流程回到授权页面
: `${hostUrl}/dashboard`; // 普通登录:直接到仪表板
const sso = btoa(
`nonce=${nonce}&return_sso_url=${encodeURIComponent(return_url)}`,

View File

@ -1,7 +1,7 @@
"use client";
import * as React from "react";
import { useRouter } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import { Loader2, MessageCircleCode } from "lucide-react";
import { cn } from "@/lib/utils";
@ -19,20 +19,38 @@ export function UserAuthForm({
const [isLoading, setIsLoading] = React.useState<boolean>(false);
const router = useRouter();
const { toast } = useToast();
const searchParams = useSearchParams();
const signIn = () => {
React.startTransition(async () => {
const response = await fetch("/api/auth/q58", { method: "POST" });
if (!response.ok || response.status !== 200) {
try {
// 构建请求体,包含 OAuth 参数
const body: Record<string, any> = {};
if (searchParams?.toString()) {
body.oauth_params = searchParams.toString();
}
const response = await fetch("/api/auth/q58", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error(response.statusText);
}
const data: DiscourseData = await response.json();
router.push(data.sso_url);
} catch (error) {
setIsLoading(false);
toast({
variant: "destructive",
title: "内部服务异常",
description: response.statusText,
description: error instanceof Error ? error.message : "未知错误",
});
} else {
let data: DiscourseData = await response.json();
router.push(data.sso_url);
}
});
};