flnxi-Wu/license-server/lib/project-auth.ts
2026-05-25 14:31:58 +08:00

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 }),
};
}
}