Вопрос проверяет понимание механизмов безопасной передачи файлов в веб-приложениях с контролем доступа на стороне клиента и сервера.
Скачивание файлов, доступ к которым ограничен правами пользователя, требует совместной работы клиентской и серверной частей приложения. Основная идея заключается в том, что запрос на файл должен сопровождаться доказательством того, что пользователь авторизован и имеет необходимые права.
На клиенте используется API fetch для выполнения авторизованного запроса. Токен (например, JWT) передаётся в стандартном заголовке Authorization. Ответ от сервера обрабатывается как бинарные данные (blob), которые затем преобразуются во временную ссылку для скачивания.
async function downloadProtectedFile(fileId) {
const token = localStorage.getItem('authToken');
const response = await fetch(`/api/files/${fileId}`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error('File download failed');
}
// Получаем бинарные данные файла
const blob = await response.blob();
// Создаём временный URL для blob
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
// Имя файла можно взять из заголовка ответа или задать явно
a.download = 'document.pdf';
document.body.appendChild(a);
a.click();
// Очистка
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}Сервер должен:
// Middleware для проверки JWT
const auth = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.sendStatus(401);
// ... проверка токена ...
req.user = decodedUser;
next();
};
app.get('/api/files/:id', auth, async (req, res) => {
const fileId = req.params.id;
// Проверка прав доступа к файлу (запрос в БД)
const hasAccess = await checkFileAccess(req.user.id, fileId);
if (!hasAccess) return res.sendStatus(403);
// Путь к файлу в файловой системе
const filePath = `/secure/storage/${fileId}.pdf`;
// Устанавливаем заголовки для скачивания
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', `attachment; filename="report_${fileId}.pdf"`);
// Отправляем файл
res.sendFile(filePath);
});Важно правильно обрабатывать ошибки (403, 404) на клиенте. Для очень больших файлов может потребоваться реализация докачки через заголовки Range. В качестве альтернативы, сервер может сгенерировать одноразовую signed-ссылку (presigned URL), например, в S3, и перенаправить на неё клиента, что разгружает основной сервер.
Вывод: Данный подход следует применять, когда необходимо контролировать доступ к файлам на уровне отдельных пользователей или ролей в веб-приложении. Он обеспечивает безопасность, так как файл никогда не доступен по публичной ссылке, а передача токена происходит через защищённое соединение HTTPS.