257 lines
5.5 KiB
TypeScript
257 lines
5.5 KiB
TypeScript
/**
|
|
* 项目权限验证工具
|
|
*/
|
|
|
|
import { NextResponse } from 'next/server';
|
|
import { mainPrisma, getProjectDb } from './db';
|
|
import { getAdminSession } from './auth';
|
|
|
|
export interface ProjectAuthResult {
|
|
success: true;
|
|
adminId: string;
|
|
projectCode: string;
|
|
projectId: string;
|
|
isSuperAdmin: boolean;
|
|
projectRole: 'admin' | 'viewer';
|
|
}
|
|
|
|
export interface ProjectAuthError {
|
|
success: false;
|
|
response: NextResponse;
|
|
}
|
|
|
|
export type AuthorizedProjectDbResult =
|
|
| {
|
|
success: true;
|
|
auth: ProjectAuthResult;
|
|
prisma: Awaited<ReturnType<typeof getProjectDb>>;
|
|
}
|
|
| ProjectAuthError;
|
|
|
|
export type PublicProjectDbResult =
|
|
| {
|
|
success: true;
|
|
prisma: Awaited<ReturnType<typeof getProjectDb>>;
|
|
}
|
|
| ProjectAuthError;
|
|
|
|
function normalizeProjectRole(role: string | null | undefined): 'admin' | 'viewer' {
|
|
return role === 'viewer' ? 'viewer' : 'admin';
|
|
}
|
|
|
|
/**
|
|
* 验证管理员对项目的访问权限
|
|
*/
|
|
export async function verifyProjectAccess(
|
|
projectCode: string
|
|
): Promise<ProjectAuthResult | ProjectAuthError> {
|
|
// 验证登录状态
|
|
const session = await getAdminSession();
|
|
if (!session) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json(
|
|
{ error: '未登录' },
|
|
{ status: 401 }
|
|
),
|
|
};
|
|
}
|
|
|
|
// 获取项目信息
|
|
const project = await mainPrisma.project.findUnique({
|
|
where: { code: projectCode },
|
|
});
|
|
|
|
if (!project) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json(
|
|
{ error: '项目不存在' },
|
|
{ status: 404 }
|
|
),
|
|
};
|
|
}
|
|
|
|
if (!project.isActive) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json(
|
|
{ error: '项目已禁用' },
|
|
{ status: 403 }
|
|
),
|
|
};
|
|
}
|
|
|
|
// 获取管理员信息
|
|
const admin = await mainPrisma.admin.findUnique({
|
|
where: { id: session.id },
|
|
include: { adminProjects: true },
|
|
});
|
|
|
|
if (!admin) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json(
|
|
{ error: '管理员不存在' },
|
|
{ status: 404 }
|
|
),
|
|
};
|
|
}
|
|
|
|
// 检查权限
|
|
let projectRole: 'admin' | 'viewer' = 'admin';
|
|
|
|
if (!admin.isSuperAdmin) {
|
|
const projectAccess = admin.adminProjects.find(
|
|
(ap: { projectId: string; role?: string | null }) => ap.projectId === project.id
|
|
);
|
|
if (!projectAccess) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json(
|
|
{ error: '无权访问此项目' },
|
|
{ status: 403 }
|
|
),
|
|
};
|
|
}
|
|
|
|
projectRole = normalizeProjectRole(projectAccess.role);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
adminId: session.id,
|
|
projectCode,
|
|
projectId: project.id,
|
|
isSuperAdmin: admin.isSuperAdmin,
|
|
projectRole,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 验证项目写权限。viewer 只能查看,不能创建、修改、禁用或删除项目数据。
|
|
*/
|
|
export async function verifyProjectWriteAccess(
|
|
projectCode: string
|
|
): Promise<ProjectAuthResult | ProjectAuthError> {
|
|
const authResult = await verifyProjectAccess(projectCode);
|
|
|
|
if (!authResult.success) {
|
|
return authResult;
|
|
}
|
|
|
|
if (!authResult.isSuperAdmin && authResult.projectRole !== 'admin') {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json(
|
|
{ error: '需要项目管理员权限' },
|
|
{ status: 403 }
|
|
),
|
|
};
|
|
}
|
|
|
|
return authResult;
|
|
}
|
|
|
|
/**
|
|
* 验证超管权限
|
|
*/
|
|
export async function verifySuperAdmin(): Promise<{ success: true; adminId: string } | ProjectAuthError> {
|
|
const session = await getAdminSession();
|
|
if (!session) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json(
|
|
{ error: '未登录' },
|
|
{ status: 401 }
|
|
),
|
|
};
|
|
}
|
|
|
|
const admin = await mainPrisma.admin.findUnique({
|
|
where: { id: session.id },
|
|
});
|
|
|
|
if (!admin || !admin.isSuperAdmin) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json(
|
|
{ error: '需要超级管理员权限' },
|
|
{ status: 403 }
|
|
),
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
adminId: session.id,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 获取项目数据库连接(带权限验证)
|
|
*/
|
|
export async function getAuthorizedProjectDb(
|
|
projectCode: string
|
|
): Promise<AuthorizedProjectDbResult> {
|
|
const authResult = await verifyProjectAccess(projectCode);
|
|
|
|
if (!authResult.success) {
|
|
return authResult;
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
auth: authResult,
|
|
prisma: await getProjectDb(projectCode),
|
|
};
|
|
}
|
|
|
|
export async function getWritableProjectDb(
|
|
projectCode: string
|
|
): Promise<AuthorizedProjectDbResult> {
|
|
const authResult = await verifyProjectWriteAccess(projectCode);
|
|
|
|
if (!authResult.success) {
|
|
return authResult;
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
auth: authResult,
|
|
prisma: await getProjectDb(projectCode),
|
|
};
|
|
}
|
|
|
|
export async function getPublicProjectDb(
|
|
projectCode: string
|
|
): Promise<PublicProjectDbResult> {
|
|
try {
|
|
return {
|
|
success: true,
|
|
prisma: await getProjectDb(projectCode),
|
|
};
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : '服务器错误';
|
|
|
|
if (message.startsWith('项目不存在')) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json({ error: '项目不存在' }, { status: 404 }),
|
|
};
|
|
}
|
|
|
|
if (message.startsWith('项目已禁用')) {
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json({ error: '项目已禁用' }, { status: 403 }),
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: false,
|
|
response: NextResponse.json({ error: '服务器错误' }, { status: 500 }),
|
|
};
|
|
}
|
|
}
|