mirror of
https://github.com/woodchen-ink/Q58Connect.git
synced 2025-07-18 05:51:55 +08:00
refactor: Simplify OAuth state management and remove cookie-based approach
This commit is contained in:
parent
d39cb2e7d5
commit
2f0d1aee47
@ -1,9 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import Cookies from "js-cookie";
|
|
||||||
import { MessageCircleCode } from "lucide-react";
|
import { MessageCircleCode } from "lucide-react";
|
||||||
|
|
||||||
import { UserAuthorize } from "@/components/auth/user-authorize";
|
import { UserAuthorize } from "@/components/auth/user-authorize";
|
||||||
@ -13,28 +10,6 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function AuthPage({ searchParams }: Props) {
|
export default function AuthPage({ searchParams }: Props) {
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// 检查是否有 OAuth 状态参数
|
|
||||||
const oauthState = Cookies.get("oauth_state");
|
|
||||||
if (oauthState) {
|
|
||||||
try {
|
|
||||||
// 解码 OAuth 参数
|
|
||||||
const params = JSON.parse(atob(oauthState));
|
|
||||||
// 删除 cookie
|
|
||||||
fetch("/api/auth/oauth-state", { method: "DELETE" }).catch(
|
|
||||||
console.error,
|
|
||||||
);
|
|
||||||
// 构建重定向 URL
|
|
||||||
const searchParams = new URLSearchParams(params);
|
|
||||||
router.push(`/oauth/authorize?${searchParams.toString()}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to process OAuth state:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [router]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
|
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
|
||||||
<div className="flex flex-col space-y-2 text-center">
|
<div className="flex flex-col space-y-2 text-center">
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ChevronLeft, MessageCircleCode } from "lucide-react";
|
import { ChevronLeft, MessageCircleCode } from "lucide-react";
|
||||||
|
|
||||||
@ -8,24 +7,7 @@ import { cn } from "@/lib/utils";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { UserAuthForm } from "@/components/auth/user-auth-form";
|
import { UserAuthForm } from "@/components/auth/user-auth-form";
|
||||||
|
|
||||||
interface Props {
|
export default function LoginPage() {
|
||||||
searchParams: { state?: string };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function LoginPage({ searchParams }: Props) {
|
|
||||||
useEffect(() => {
|
|
||||||
// 如果有 state 参数,保存到 cookie
|
|
||||||
if (searchParams.state) {
|
|
||||||
fetch("/api/auth/oauth-state", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ state: searchParams.state }),
|
|
||||||
}).catch(console.error);
|
|
||||||
}
|
|
||||||
}, [searchParams.state]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Link
|
<Link
|
||||||
@ -48,7 +30,7 @@ export default function LoginPage({ searchParams }: Props) {
|
|||||||
<span style={{ fontFamily: "Bahamas Bold" }}>Q58 Connect</span>
|
<span style={{ fontFamily: "Bahamas Bold" }}>Q58 Connect</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserAuthForm oauthState={searchParams.state} />
|
<UserAuthForm />
|
||||||
<p className="px-8 text-center text-sm text-muted-foreground">
|
<p className="px-8 text-center text-sm text-muted-foreground">
|
||||||
By clicking continue, you agree to our{" "}
|
By clicking continue, you agree to our{" "}
|
||||||
<Link
|
<Link
|
||||||
|
@ -21,10 +21,7 @@ export default async function OAuthAuthorization({
|
|||||||
// 检查用户是否已登录
|
// 检查用户是否已登录
|
||||||
const user = await getCurrentUser();
|
const user = await getCurrentUser();
|
||||||
if (!user?.id) {
|
if (!user?.id) {
|
||||||
// 将 OAuth 参数编码为 base64
|
redirect("/sign-in");
|
||||||
const encodedParams = btoa(JSON.stringify(searchParams));
|
|
||||||
// 重定向到登录页面,将 OAuth 参数作为查询参数传递
|
|
||||||
redirect(`/sign-in?state=${encodedParams}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证必要的参数
|
// 验证必要的参数
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
import { cookies } from "next/headers";
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
|
||||||
try {
|
|
||||||
const { state } = await req.json();
|
|
||||||
cookies().set("oauth_state", state, {
|
|
||||||
maxAge: 60 * 10, // 10分钟过期
|
|
||||||
path: "/",
|
|
||||||
httpOnly: true,
|
|
||||||
secure: process.env.NODE_ENV === "production",
|
|
||||||
});
|
|
||||||
return NextResponse.json({ success: true });
|
|
||||||
} catch (error) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Failed to save state" },
|
|
||||||
{ status: 500 },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function DELETE() {
|
|
||||||
cookies().delete("oauth_state");
|
|
||||||
return NextResponse.json({ success: true });
|
|
||||||
}
|
|
@ -11,22 +11,7 @@ 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 return_url = `${hostUrl}/authorize`;
|
||||||
// 检查是否存在 OAuth 状态
|
|
||||||
const oauthState = cookies().get("oauth_state");
|
|
||||||
let return_url = `${hostUrl}/dashboard`; // 默认重定向到仪表板
|
|
||||||
|
|
||||||
if (oauthState) {
|
|
||||||
try {
|
|
||||||
// 解码并重建 OAuth URL
|
|
||||||
const params = JSON.parse(atob(oauthState.value));
|
|
||||||
const searchParams = new URLSearchParams(params);
|
|
||||||
return_url = `${hostUrl}/oauth/authorize?${searchParams.toString()}`;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to process OAuth state:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sso = btoa(`nonce=${nonce}&return_sso_url=${return_url}`);
|
const sso = btoa(`nonce=${nonce}&return_sso_url=${return_url}`);
|
||||||
const sig = hmacSHA256(sso, clientSecret).toString(Hex);
|
const sig = hmacSHA256(sso, clientSecret).toString(Hex);
|
||||||
|
|
||||||
|
@ -12,15 +12,10 @@ interface DiscourseData {
|
|||||||
sso_url: string;
|
sso_url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
||||||
oauthState?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function UserAuthForm({
|
export function UserAuthForm({
|
||||||
className,
|
className,
|
||||||
oauthState,
|
|
||||||
...props
|
...props
|
||||||
}: UserAuthFormProps) {
|
}: React.HTMLAttributes<HTMLDivElement>) {
|
||||||
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();
|
||||||
@ -28,17 +23,6 @@ export function UserAuthForm({
|
|||||||
const signIn = () => {
|
const signIn = () => {
|
||||||
React.startTransition(async () => {
|
React.startTransition(async () => {
|
||||||
try {
|
try {
|
||||||
// 如果有 OAuth 参数,先保存到 cookie
|
|
||||||
if (oauthState) {
|
|
||||||
await fetch("/api/auth/oauth-state", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ state: oauthState }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch("/api/auth/q58", {
|
const response = await fetch("/api/auth/q58", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user