/** * 验证用户是否有权访问指定文档 * * 权限验证逻辑: * 1. 检查文档是否属于指定的任务 * 2. 检查用户是否是该任务的参与者(评审员或发起人) * 3. 防止用户通过修改 URL 参数访问未授权的文档 */ import { postgrestGet } from "../postgrest-client"; interface DocumentAccessCheckParams { documentId: string | number; taskId: string | number; userId: number; jwtToken?: string; } interface DocumentAccessCheckResult { hasAccess: boolean; reason?: string; userRole?: 'assigner' | 'assignee' | 'none'; } /** * 验证文档访问权限 * @param params 验证参数 * @returns 验证结果 */ export async function verifyDocumentAccess( params: DocumentAccessCheckParams ): Promise { const { documentId, taskId, userId, jwtToken } = params; try { // 1. 检查文档是否属于该任务(通过 cross_task_document_mapping 表) const documentMappingResponse = await postgrestGet('cross_task_document_mapping', { select: 'task_id,document_id', filter: { task_id: `eq.${taskId}`, document_id: `eq.${documentId}` }, token: jwtToken }); if (documentMappingResponse.error) { console.error('❌ [verifyDocumentAccess] 查询文档-任务映射失败:', documentMappingResponse.error); return { hasAccess: false, reason: '查询文档-任务映射失败' }; } // 提取数据 const mappingData = Array.isArray(documentMappingResponse.data) ? documentMappingResponse.data : []; // 文档不属于该任务 if (mappingData.length === 0) { console.warn(`⚠️ [verifyDocumentAccess] 文档 ${documentId} 不属于任务 ${taskId}`); return { hasAccess: false, reason: '文档不属于该任务' }; } // 2. 检查用户是否是该任务的参与者 const taskResponse = await postgrestGet('cross_examination_tasks', { select: 'assigner_id,assignee_ids', filter: { id: `eq.${taskId}` }, token: jwtToken }); if (taskResponse.error) { console.error('❌ [verifyDocumentAccess] 查询任务信息失败:', taskResponse.error); return { hasAccess: false, reason: '查询任务信息失败' }; } const taskData = Array.isArray(taskResponse.data) ? taskResponse.data[0] : null; if (!taskData) { console.warn(`⚠️ [verifyDocumentAccess] 任务 ${taskId} 不存在`); return { hasAccess: false, reason: '任务不存在' }; } // 3. 验证用户身份 const isAssigner = taskData.assigner_id === userId; const assigneeIds = Array.isArray(taskData.assignee_ids) ? taskData.assignee_ids : []; const isAssignee = assigneeIds.includes(userId); if (isAssigner) { console.log(`✅ [verifyDocumentAccess] 用户 ${userId} 是任务 ${taskId} 的发起人,允许访问文档 ${documentId}`); return { hasAccess: true, userRole: 'assigner' }; } if (isAssignee) { console.log(`✅ [verifyDocumentAccess] 用户 ${userId} 是任务 ${taskId} 的评审员,允许访问文档 ${documentId}`); return { hasAccess: true, userRole: 'assignee' }; } // 用户既不是发起人也不是评审员 console.warn(`⚠️ [verifyDocumentAccess] 用户 ${userId} 无权访问任务 ${taskId} 的文档 ${documentId}`); return { hasAccess: false, reason: '您没有权限访问该文档', userRole: 'none' }; } catch (error) { console.error('❌ [verifyDocumentAccess] 验证失败:', error); return { hasAccess: false, reason: error instanceof Error ? error.message : '权限验证失败' }; } } /** * 快速验证文档访问权限(仅返回布尔值) * @param params 验证参数 * @returns 是否有权限访问 */ export async function canAccessDocument( params: DocumentAccessCheckParams ): Promise { const result = await verifyDocumentAccess(params); return result.hasAccess; }