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