refactor(auth): switch to class-based social login and v4 route handler

Migrate from function-based social login helpers (`facebookLogin`, `googleLogin`)
to class-based services (`new FacebookLogin().signIn()`, `new GoogleLogin().signIn()`),
updating call sites in `AuthFacebookPanel` and `SplashButton` with try/catch error
handling. The NextAuth route handler is also refactored to the v4 pattern, importing
pre-built `GET` / `POST` exports from `@/lib/auth/nextauth` instead of constructing
the handler inline with `NextAuth(authOptions)`.
This commit is contained in:
2026-06-10 15:34:52 +08:00
parent 90bb711a45
commit d70e61f92e
115 changed files with 9004 additions and 493 deletions
+18 -9
View File
@@ -2,17 +2,20 @@
* Next.js 16 Proxy(原 `middleware.ts`
*
* 行为(鉴权路由统一在此处理,业务层组件不再做 auth-driven 跳转):
* - 已登录(`cozsweet_authed` cookie 存在)访问 `/splash` 或 `/auth`
* - 已登录(NextAuth `next-auth.session-token` cookie 存在)访问 `/splash` 或 `/auth`
* → 308 重定向到 `/chat`
* - 未登录(cookie 缺失)访问 `/chat` 或 `/sidebar`
* → 308 重定向到 `/splash`(首界面)
* - 其他情况透传(`NextResponse.next()`
*
* 重要约束:
* - **不**检查 NextAuth 自带的 `next-auth.session-token`:统一用自定义
* `cozsweet_authed` 信号,社交 / 邮箱登录出口都同步设/清这个 cookie
* - 真正的鉴权门在 Client 侧 `useAuthGate()`(用 `useSession()`),用于 UI 状态。
* - **不**做自定义 cookie 持久化:统一用 NextAuth 内置 `next-auth.session-token` /
* `__Secure-next-auth.session-token`v5 默认 httpOnly + secure)作信号
* - 真正的鉴权门在 Client 侧 `AuthGate.useState()`(用 `useSession()`),用于 UI 状态。
* - 路由跳转(**唯一**鉴权跳转点)由本 proxy 集中处理。
* - 副作用:邮箱登录用户(不走 NextAuth)不会被本 proxy 识别为已登录。
* 邮箱登录在后续轮次若要恢复 proxy 行为,需引入 NextAuth EmailProvider 或独立
* email-session 体系。
*
* Next 16 重要变更(参见 `node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/proxy.md`):
* - 文件从 `middleware.ts` 重命名为 `proxy.ts``middleware` 仍可用但已 deprecated。
@@ -31,8 +34,11 @@ import {
ROUTES,
} from "@/router/routes";
/** 路由信号 cookie 名(由 `src/app/api/auth/marker/route.ts` 写 */
const AUTH_COOKIE = "cozsweet_authed";
/** NextAuth 内置 session cookie 名(v5 默认 httpOnly */
const SESSION_COOKIE_NAMES = [
"next-auth.session-token",
"__Secure-next-auth.session-token",
];
function isAuthOnlyRoute(pathname: string): boolean {
return (AUTH_ONLY_ROUTES as readonly string[]).includes(pathname);
@@ -48,17 +54,20 @@ function isProtectedRoute(pathname: string): boolean {
export function proxy(request: NextRequest) {
const { pathname } = request.nextUrl;
const hasAuth = Boolean(request.cookies.get(AUTH_COOKIE)?.value);
// 检查 NextAuth session cookie 存在性
const hasSession = SESSION_COOKIE_NAMES.some(
(name) => Boolean(request.cookies.get(name)?.value),
);
// 已登录访问未登录专属页 → /chat
if (hasAuth && isAuthOnlyRoute(pathname)) {
if (hasSession && isAuthOnlyRoute(pathname)) {
const url = request.nextUrl.clone();
url.pathname = ROUTES.chat;
return NextResponse.redirect(url, 308);
}
// 未登录访问登录态专属页 → /splash(首界面)
if (!hasAuth && isProtectedRoute(pathname)) {
if (!hasSession && isProtectedRoute(pathname)) {
const url = request.nextUrl.clone();
url.pathname = ROUTES.splash;
return NextResponse.redirect(url, 308);