import { NextRequest, NextResponse } from 'next/server'; import { prisma } from '@/lib/db'; import { authenticateRequest, type JwtPayload } from '@/lib/auth'; import { unauthorized, forbidden } from '@/lib/api-response'; export type PermissionAction = 'create' | 'read' | 'update' | 'delete' | 'publish'; export interface Permission { roleCode: string; modelCode: string; action: PermissionAction; } /** * 判断一组角色是否对指定模型和操作具备权限 * super_admin 默认拥有所有权限 */ export function hasPermission( roles: string[], modelCode: string, action: PermissionAction, permissions: Permission[] ): boolean { if (roles.includes('super_admin')) return true; return permissions.some( (p) => roles.includes(p.roleCode) && p.modelCode === modelCode && p.action === action ); } /** * 查询数据库判断指定用户是否具备权限 */ export async function checkUserPermission( userId: string, modelCode: string, action: PermissionAction ): Promise { const userRoles = await prisma.userRole.findMany({ where: { userId }, }); const roleCodes = userRoles.map((ur) => (ur as { roleCode: string }).roleCode); if (roleCodes.includes('super_admin')) return true; if (roleCodes.length === 0) return false; const permissionRecords = await prisma.permission.findMany({ where: { roleCode: { in: roleCodes } }, }); const permissions = permissionRecords.map((p) => ({ roleCode: (p as { roleCode: string }).roleCode, modelCode: (p as { modelCode: string }).modelCode, action: (p as { action: PermissionAction }).action, })); return hasPermission(roleCodes, modelCode, action, permissions); } export interface PermissionSuccess { user: JwtPayload; } export interface PermissionFailure { response: NextResponse; } /** * 校验请求是否已认证并具备指定权限 * 通过返回 { user },失败返回 { response } */ export async function requirePermission( request: NextRequest, modelCode: string, action: PermissionAction ): Promise { const user = authenticateRequest(request); if (!user) { return { response: unauthorized() }; } const allowed = await checkUserPermission(user.userId, modelCode, action); if (!allowed) { return { response: forbidden() }; } return { user }; }