Files
hair-keeper/src/middleware.ts

73 lines
2.0 KiB
TypeScript

import { withAuth } from "next-auth/middleware"
import { NextResponse } from "next/server"
import { getMenuPermission } from "@/constants/menu"
import { evaluatePermissionExpression } from "@/constants/permissions"
export default withAuth(
// `withAuth` 会自动检查 JWT token
function middleware(req) {
const token = req.nextauth.token
const pathname = req.nextUrl.pathname
// 如果用户已登录且访问登录页面,重定向到首页
if (pathname === "/login" && token) {
return NextResponse.redirect(new URL("/", req.url))
}
// 如果访问 403 页面,直接放行
if (pathname === "/error/403") {
return NextResponse.next()
}
// 检查路由权限
if (token) {
const requiredPermission = getMenuPermission(pathname)
// 如果找到了权限要求
if (requiredPermission !== undefined) {
const userPermissions = (token.permissions as string[]) || []
const isSuperAdmin = token.isSuperAdmin as boolean
// 超级管理员拥有所有权限
if (isSuperAdmin) {
return NextResponse.next()
}
// 检查用户是否有所需权限
if (!evaluatePermissionExpression(requiredPermission, userPermissions)) {
return NextResponse.redirect(new URL("/error/403", req.url))
}
}
}
return NextResponse.next()
},
{
callbacks: {
authorized: ({ token, req }) => {
// 如果访问登录页面
if (req.nextUrl.pathname === "/login") {
return true
}
// 其他路由需要有效的 token
return !!token
},
},
}
)
// 配置需要保护的路由
export const config = {
matcher: [
/*
* 匹配所有路径除了:
* - /api/auth/* (NextAuth.js 路由)
* - /_next/static (static files)
* - /_next/image (image optimization files)
* - /favicon.ico (favicon file)
* - /public/* (public files)
*/
"/((?!api/auth|_next/static|_next/image|favicon.ico|public).*)",
],
}