Создать временную ссылку для скачивания

Я использую ASP.NET
Мне нужно дать пользователю временную ссылку для скачивания файла с сервера.
Это должна быть временная ссылка (страница), которая доступна в течение короткого времени (например, 12 часов). Как я могу создать эту ссылку (или временную веб-страницу со ссылкой)?

5 ответов

Вот достаточно полный пример.

Сначала функция для создания короткой шестнадцатеричной строки с использованием секретной соли плюс время истечения:

public static string MakeExpiryHash(DateTime expiry)
{
    const string salt = "some random bytes";
    byte[] bytes = Encoding.UTF8.GetBytes(salt + expiry.ToString("s"));
    using (var sha = System.Security.Cryptography.SHA1.Create())
        return string.Concat(sha.ComputeHash(bytes).Select(b => b.ToString("x2"))).Substring(8);
}

Затем фрагмент, который генерирует ссылку с истечением одной недели:

DateTime expires = DateTime.Now + TimeSpan.FromDays(7);
string hash = MakeExpiryHash(expires);
string link = string.Format("http://myhost/Download?exp={0}&k={1}", expires.ToString("s"), hash);

Наконец, страница загрузки для отправки файла, если была дана действительная ссылка:

DateTime expires = DateTime.Parse(Request.Params["exp"]);
string hash = MakeExpiryHash(expires);
if (Request.Params["k"] == hash)
{
    if (expires < DateTime.UtcNow)
    {
        // Link has expired
    }
    else
    {
        string filename = "<Path to file>";
        FileInfo fi = new FileInfo(Server.MapPath(filename));
        Response.ContentType = "application/octet-stream";
        Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
        Response.AddHeader("Content-Length", fi.Length.ToString());
        Response.WriteFile(fi.FullName);
        Response.Flush();
    }
}
else
{
    // Invalid link
}

Который вы, безусловно, должны обернуть при обработке исключений, чтобы перехватить искаженные запросы

http://example.com/download/document.pdf?token=<token>

<token> часть здесь ключевая. Если вы не хотите задействовать базу данных, зашифруйте время создания ссылки, преобразуйте ее в безопасное для URL представление Base64 и предоставьте пользователю этот URL. Когда это запрошено, расшифруйте token и сравните сохраненную там дату с текущей датой и временем.

Кроме того, вы можете иметь отдельный DownloadTokens стол, который будет отображать карту tokens (которые могут быть GUID) до срока годности.

Добавьте временную метку к URL в строке запроса:

page.aspx?time=2011-06-22T22:12

Проверьте отметку времени относительно текущего времени.

Чтобы пользователь сам не изменил временную метку, также вычислите некоторый секретный хеш по временной метке, а также добавьте это в строку запроса:

page.aspx?time=2011-06-22T22:12&timehash=4503285032

В качестве хэша вы можете сделать что-то вроде суммы всех полей в DateTime по модулю некоторого простого числа или суммы SHA1 строкового представления времени. Теперь пользователь не сможет изменить временную метку, не зная правильный хеш. В вашем page.aspx вы проверяете данный хеш против хеша метки времени.

Есть миллион способов сделать это.

То, как я однажды сделал это для проекта, заключалось в том, чтобы сгенерировать уникальный ключ и использовать скрипт динамического загрузчика для потоковой передачи файла. когда был сделан запрос файла, ключ был сгенерирован и сохранен в БД с указанием времени создания и запрошенного файла. Вы строите ссылку на скрипт загрузки и передаете ключ. оттуда было достаточно легко следить за истечением срока действия.

Лля

Я предполагаю, что вы не требуете никакой аутентификации, и безопасность не является проблемой - то есть, если кто-то получит URL, он также сможет загрузить файл.

Лично я бы создал HttpHandler, а затем создал бы уникальную строку, которую вы можете добавить к URL.

Затем в рамках ProcessRequest void протестируйте закодированный параметр, чтобы увидеть, является ли он все еще жизнеспособным (с указанным периодом времени), если это так, используйте BinaryWrite для визуализации файла или, если нет, вы можете визуализировать некоторый HTML с помощью Response.Write("Expired")

Что-то вроде:

открытый класс TimeHandler: IHttpHandler, IRequiresSessionState
{
    public void ProcessRequest (контекст HttpContext)
    {

        if( this.my_check_has_expired( this.Context.Request.Params["my_token"]))
        {
            // истек 

            context.Response.Write( "Срок действия URL истек");
            вернуть;
        }

        // Визуализация файла
        Stream stream = новый FileStream( File_Name, FileMode.Open);

        /* читать байты из файла */
        byte[] aBytes = новый byte[(int)oStream.Length];
        stream.Read( aBytes, 0, (int)oStream.Length);
        stream.Close(); 

        // Установить заголовки
        context.Response.AddHeader( "Content-Length", aBytes.Length.ToString());
        // ContentType должен быть установлен также вы можете принудительно сохранить как, если вам нужно

        // Отправить буфер
        context.Response.BinaryWrite( aBytes);                            

    }
}

Затем вам нужно настроить обработчик в IIS, но он немного отличается в зависимости от используемой версии.

Другие вопросы по тегам