117 lines
3.4 KiB
TypeScript
117 lines
3.4 KiB
TypeScript
import { NextResponse } from 'next/server';
|
||
import type { NextRequest } from 'next/server';
|
||
|
||
// 需要认证的路由
|
||
const protectedRoutes = [
|
||
'/profile',
|
||
'/profile/account',
|
||
'/profile/edit',
|
||
'/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 proxy(request: NextRequest) {
|
||
const { pathname } = request.nextUrl;
|
||
|
||
// 获取现有设备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;
|
||
} 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')
|
||
);
|
||
|
||
// 如果是受保护的路由但用户未登录,重定向到登录页
|
||
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,
|
||
},
|
||
});
|
||
|
||
// 如果locale cookie不存在,设置为en-US
|
||
if (!request.cookies.get('locale')?.value) {
|
||
response.cookies.set('locale', 'en-US', {
|
||
maxAge: 365 * 24 * 60 * 60, // 365天
|
||
httpOnly: false,
|
||
secure: process.env.NODE_ENV === 'production',
|
||
sameSite: 'lax',
|
||
path: '/',
|
||
});
|
||
}
|
||
|
||
// 如果需要设置设备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: '/',
|
||
});
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
export const config = {
|
||
matcher: [
|
||
// 匹配所有路径,除了静态文件和API路由
|
||
'/((?!api|_next/static|_next/image|favicon.ico|public).*)',
|
||
],
|
||
};
|