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

View File

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

View File

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