crush-level-web/src/middleware.ts

127 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
// 需要认证的路由
const protectedRoutes = [
"/profile",
"/profile/account",
"/profile/edit",
"/create",
"/settings",
"/login/fields",
"/chat",
"/contact",
"/vip",
"/wallet",
"/wallet/transactions",
"/crushcoin",
]
// 已登录用户不应该访问的路由
const authRoutes = [
"/login",
]
const DEVICE_ID_COOKIE_NAME = 'sd'
// 生成设备ID
function generateDeviceId(userAgent?: string): string {
const timestamp = Date.now().toString(36)
const randomStr = Math.random().toString(36).substring(2, 15)
const browserInfo = userAgent
? userAgent.replace(/\s/g, '').substring(0, 10)
: 'server'
return `did_${timestamp}_${randomStr}_${browserInfo}`.toLowerCase()
}
export default function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
// console.log('🔄 [MIDDLEWARE] 开始处理路径:', pathname)
// console.log('🔄 [MIDDLEWARE] 请求方法:', request.method)
// console.log('🔄 [MIDDLEWARE] User-Agent:', request.headers.get('user-agent')?.substring(0, 50))
// console.log('🔄 [MIDDLEWARE] 请求头:', Object.fromEntries(request.headers.entries()))
// 获取现有设备ID
let deviceId = request.cookies.get(DEVICE_ID_COOKIE_NAME)?.value
let needSetCookie = false
if (!deviceId) {
// 生成新的设备ID
const userAgent = request.headers.get('user-agent') || undefined
deviceId = generateDeviceId(userAgent)
needSetCookie = true
// console.log('🆕 [MIDDLEWARE] 生成新设备ID:', deviceId)
} else {
console.log('✅ [MIDDLEWARE] 获取现有设备ID:', deviceId)
}
// 认证逻辑
const token = request.cookies.get("st")?.value
const isAuthenticated = !!token
const isProtectedRoute = protectedRoutes.some(route => pathname.startsWith(route))
const isAuthRoute = authRoutes.some(route => pathname.startsWith(route) && !pathname.startsWith("/login/fields"))
// console.log('🔑 [MIDDLEWARE] 认证状态:', {
// isAuthenticated,
// pathname,
// isProtectedRoute,
// isAuthRoute,
// token: token ? '存在' : '不存在'
// });
// 如果是受保护的路由但用户未登录,重定向到登录页
if (isProtectedRoute && !isAuthenticated) {
console.log('🚫 [MIDDLEWARE] 重定向到登录页:', pathname)
const loginUrl = new URL("/login", request.url)
loginUrl.searchParams.set("redirect", pathname)
return NextResponse.redirect(loginUrl)
}
// 如果已登录用户访问认证页面,重定向到首页
if (isAuthRoute && isAuthenticated) {
console.log('🔄 [MIDDLEWARE] 已登录用户重定向到首页:', pathname)
return NextResponse.redirect(new URL("/", request.url))
}
// 在请求头中添加认证状态和设备ID供服务端组件使用
const requestHeaders = new Headers(request.headers)
requestHeaders.set("x-authenticated", isAuthenticated.toString())
requestHeaders.set("x-device-id", deviceId) // 确保设备ID被传递
if (token) {
requestHeaders.set("x-auth-token", token)
}
// 创建响应
const response = NextResponse.next({
request: {
headers: requestHeaders,
}
})
// 如果需要设置设备ID cookie
if (needSetCookie) {
response.cookies.set(DEVICE_ID_COOKIE_NAME, deviceId, {
maxAge: 365 * 24 * 60 * 60, // 365天
httpOnly: false,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/'
})
}
if (pathname.startsWith("/@")) {
const userId = pathname.slice(2); // 去掉/@
return NextResponse.rewrite(new URL(`/user/${userId}`, request.url));
}
console.log('✅ [MIDDLEWARE] 成功处理完毕:', pathname)
return response
}
export const config = {
matcher: [
// 匹配所有路径除了静态文件和API路由
"/((?!api|_next/static|_next/image|favicon.ico|public).*)",
],
}