-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmiddleware.ts
More file actions
131 lines (112 loc) · 3.28 KB
/
middleware.ts
File metadata and controls
131 lines (112 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { jwtVerify } from 'jose';
// 需要登录才能访问的路由
const protectedRoutes = [
'/websites',
'/admin',
];
// 公开路由
const publicRoutes = [
'/login',
'/register',
];
const SECRET_KEY = new TextEncoder().encode(process.env.JWT_SECRET || 'your-secret-key');
// 验证 JWT token
async function verifyAuth(token: string) {
try {
const { payload } = await jwtVerify(token, SECRET_KEY);
return payload as { userId: string; username: string };
} catch {
return null;
}
}
export async function middleware(request: NextRequest) {
const token = request.cookies.get('token')?.value;
const { pathname } = request.nextUrl;
// 跳过静态资源
if (
pathname.startsWith('/_next') ||
pathname.startsWith('/static')
) {
return NextResponse.next();
}
// 允许访问的公开 API 路由
const publicApiRoutes = [
'/api/auth/login',
'/api/auth/register',
'/api/auth/me', // 添加/api/auth/me到公开路由,让前端能检查登录状态
'/api/share',
'/api/featured-websites',
'/api/get-models', // 允许获取模型列表,用于显示提供商选项
'/api/get-default-provider' // 允许获取默认提供商
];
// 如果是 API 路由
if (pathname.startsWith('/api')) {
// 如果是公开 API 路由,直接放行
if (publicApiRoutes.some(route => pathname.startsWith(route))) {
return NextResponse.next();
}
// 其他 API 路由需要验证 token
if (!token) {
return new NextResponse(
JSON.stringify({ error: 'Please login first' }),
{ status: 401, headers: { 'Content-Type': 'application/json' } }
);
}
const user = await verifyAuth(token);
if (!user) {
return new NextResponse(
JSON.stringify({ error: 'Session expired, please login again' }),
{ status: 401, headers: { 'Content-Type': 'application/json' } }
);
}
return NextResponse.next();
}
const isPublicRoute = publicRoutes.some(route => pathname.startsWith(route));
const isProtectedRoute = protectedRoutes.some(route => pathname.startsWith(route));
// 验证用户状态
const user = token ? await verifyAuth(token) : null;
// 处理公开路由(登录、注册)
if (isPublicRoute) {
// 如果用户已登录且尝试访问登录/注册页面,重定向到首页
if (user) {
return NextResponse.redirect(new URL('/', request.url));
}
return NextResponse.next();
}
// 处理受保护路由
if (isProtectedRoute) {
// 如果用户未登录或token无效,重定向到登录页
if (!user) {
const url = new URL('/login', request.url);
url.searchParams.set('from', pathname);
return NextResponse.redirect(url);
}
return NextResponse.next();
}
// 处理首页
if (pathname === '/') {
return NextResponse.next();
}
return NextResponse.next();
}
export const config = {
matcher: [
/*
* 匹配所有路由:
* - `/`
* - `/websites` 和其子路由
* - `/admin` 和其子路由
* - `/login`
* - `/register`
* - `/api` 和其子路由
*/
'/',
'/websites/:path*',
'/admin/:path*',
'/login',
'/register',
'/api/:path*'
],
};