forked from tangly1024/NotionNext
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmiddleware.ts
132 lines (125 loc) · 3.91 KB
/
middleware.ts
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
132
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
import { NextRequest, NextResponse } from 'next/server'
import {
checkStrIsNotionId,
checkStrIsUuid,
getLastPartOfUrl
} from '@/lib/utils'
import { idToUuid } from 'notion-utils'
import BLOG from './blog.config'
import { upstashRedisClient } from '@/lib/cache/upstash_redis_cache'
/**
* Clerk 身份验证中间件
*/
export const config = {
// 这里设置白名单,防止静态资源被拦截
matcher: ['/((?!.*\\..*|_next|/sign-in|/auth).*)', '/', '/(api|trpc)(.*)']
}
// 限制登录访问的路由
const isTenantRoute = createRouteMatcher([
'/user/organization-selector(.*)',
'/user/orgid/(.*)',
'/dashboard',
'/dashboard/(.*)'
])
// 限制权限访问的路由
const isTenantAdminRoute = createRouteMatcher([
'/admin/(.*)/memberships',
'/admin/(.*)/domain'
])
/**
* 没有配置权限相关功能的返回
* @param req
* @param ev
* @returns
*/
// eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
const noAuthMiddleware = async (req: NextRequest, ev: any) => {
// 如果没有配置 Clerk 相关环境变量,返回一个默认响应或者继续处理请求
if (BLOG['UUID_REDIRECT']) {
let lastPart = getLastPartOfUrl(req.nextUrl.pathname) as string
if (checkStrIsNotionId(lastPart)) {
lastPart = idToUuid(lastPart)
}
if (checkStrIsUuid(lastPart)) {
let redirectJson: Record<string, string | null> = {}
if (upstashRedisClient) {
const redisResult = (await upstashRedisClient.hget(
BLOG.REDIRECT_CACHE_KEY,
lastPart
)) as string
redirectJson = {
[lastPart]: redisResult
}
} else if (BLOG.REDIS_URL) {
try {
const redisResponse = await fetch(
`${req.nextUrl.origin}/api/redirect`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
lastPart: lastPart
})
}
)
const redisResult = await redisResponse?.json()
redirectJson = {
[lastPart]: redisResult?.data
}
} catch (e) {
console.warn('读取Redis失败', e)
}
} else {
try {
const response = await fetch(`${req.nextUrl.origin}/redirect.json`)
if (response.ok) {
redirectJson = (await response.json()) as Record<string, string>
}
} catch (err) {
console.error('Error fetching static file:', err)
}
}
if (redirectJson[lastPart]) {
const redirectToUrl = req.nextUrl.clone()
redirectToUrl.pathname = '/' + redirectJson[lastPart]
console.log(
`redirect from ${req.nextUrl.pathname} to ${redirectToUrl.pathname}`
)
return NextResponse.redirect(redirectToUrl, 308)
}
}
}
return NextResponse.next()
}
/**
* 鉴权中间件
*/
const authMiddleware = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
? clerkMiddleware(async (auth, req) => {
const { userId } = auth()
// 处理 /dashboard 路由的登录保护
if (isTenantRoute(req)) {
if (!userId) {
// 用户未登录,重定向到 /sign-in
const url = new URL('/sign-in', req.url)
url.searchParams.set('redirectTo', req.url) // 保存重定向目标
return NextResponse.redirect(url)
}
}
// 处理管理员相关权限保护
if (isTenantAdminRoute(req)) {
auth().protect(has => {
return (
has({ permission: 'org:sys_memberships:manage' }) ||
has({ permission: 'org:sys_domains_manage' })
)
})
}
// 默认继续处理请求
return NextResponse.next()
})
: noAuthMiddleware
export default authMiddleware