Сеансы и безопасность

Сеансы документов и контроль доступа

Токен Doconut обладает большой силой: любой, кто его предъявит, может запросить каждую страницу документа, если он не привязан к открывающему сеансу. Эта страница объясняет, что хранится в сеансе, как долго он живёт и какие проверки включаются по умолчанию функцией UseDoconut().

Что содержит сеанс документа

Каждый успешный вызов OpenDocumentAsync создаёт один сеанс в IMemoryCache:

  • загруженный просмотрщик формата (экземпляр движка документа, содержащий разобранный документ),
  • состояние каждой страницы — вращение, отражения и данные аннотаций, которые пользователь применяет в виджете,
  • необязательный поисковый индекс, создаваемый лениво при первом поиске (или загружаемый из предварительно построенного файла .srh в сценариях веб‑ферм),
  • водяной знак сеанса из DocOptions.Watermark.

Время жизни

Сеансы истекают по скользящему окну: DocOptions.TimeOut минут (по умолчанию 60), сбрасываемому каждым запросом, предъявляющим токен. Когда сеанс удаляется — по истечении срока или через CloseDocument(token) — его callback освобождает движок документа и сразу же освобождает связанную память.

csharp
// Краткоживущий сеанс для однократного предварительного просмотра
var token = await viewer.OpenDocumentAsync(path, new DocOptions { TimeOut = 10 });

Запрос с истёкшим токеном получает изображение ошибки с надписью Document session not found. Please re-open document. — клиент должен открыть документ заново, чтобы получить новый токен.

Встроенная привязка токенов

При UnsafeMode = false (по умолчанию) OpenDocumentAsync привязывает новый токен к ASP.NET‑сеансу HTTP‑запроса, который его открыл, записывая маркер secure-{token} в этот сеанс. Промежуточное ПО Doconut затем отказывает в обслуживании страниц любому другому браузерному сеансу:

  • Другой браузер/сеанс, представляющий украденный токен → изображение ошибки You Are Not Authorized To View This Page.
  • Промежуточное ПО сеанса не зарегистрировано → HTTP 500 Session middleware not configured. Call UseSession() before UseDoconut().

Именно поэтому Quick Start требует вызвать AddSession() + app.UseSession() до ветки Doconut. Две практические последствия:

  • Клиент должен отправлять cookie сеанса ASP.NET вместе с запросами страниц. Настройки кросс‑домена, которые удаляют cookie (или API‑клиент без cookie‑хранилища), не пройдут проверку — это работа функции, а не ошибка.
  • options.UnsafeMode = true полностью отключает привязку. Она существует для контролируемых сценариев (например, рендеринг сервер‑к‑серверу); оставляйте её false в продакшене.

Привязка токенов управляется исключительно этим глобальным переключателем UnsafeMode — по умолчанию он включён (UnsafeMode = false) и применяется ко всем сеансам. Отказ от привязки на уровне отдельного документа невозможен; установка UnsafeMode = true отключает привязку глобально.

Права доступа и аутентифицированные пользователи

Когда UnsafeMode = false, UseDoconut() автоматически вставляет DocumentAccessMiddleware перед промежуточным ПО страниц. Не регистрируйте его повторно. Когда запрос содержит токен, middleware ищет право доступа, записанное при открытии документа, и авторизует только при выполнении всех условий:

  1. существует грант для токена,
  2. он не истёк (время жизни гранта = TimeOut документа),
  3. идентификатор ASP.NET‑сеанса запроса совпадает с тем, который открыл документ,
  4. если открывший был аутентифицирован, claim NameIdentifier запрашивающего пользователя также совпадает.

При несоответствии возвращается 403 — в виде PNG‑изображения ошибки для запросов страниц/миниатюр, иначе в виде простого текста. Сообщение и ключ запроса токена берутся из DocumentSecurityOptions (TokenQueryKey, по умолчанию "token"; UnauthorizedMessage, по умолчанию "You Are Not Authorized To View This Page."). Настройте эти параметры через DI ASP.NET Core до построения приложения. Если состояние сеанса недоступно, middleware закрывается с ошибкой HTTP 500: ASP.NET Session is required for Doconut document security.

csharp
builder.Services.Configure<Doconut.Security.DocumentSecurityOptions>(options =>
{
    options.TokenQueryKey = "token";
    options.UnauthorizedMessage = "You Are Not Authorized To View This Page.";
});

Ядро middleware страниц затем проверяет маркер secure-{token} в сеансе перед обслуживанием документа. При UnsafeMode = true UseDoconut() пропускает middleware доступа, и проверка маркера также отключается.

Отзыв

CloseDocument(token) не только освобождает память — он также удаляет маркер secure-{token} и отзывает право доступа, поэтому закрытый токен сразу становится недействительным на обоих уровнях безопасности.

Чеклист для продакшна

  • Оставляйте UnsafeMode = false (по умолчанию) — этот глобальный переключатель привязывает токены к сеансам.
  • Регистрируйте AddDistributedMemoryCache() (в MVC и Razor Pages приложениях он уже есть) и AddSession(), и вызывайте app.UseSession() перед веткой промежуточного ПО Doconut.
  • Убедитесь, что политика cookie сеанса позволяет запросам виджета передавать cookie (SameSite, HTTPS).
  • Используйте CloseDocument, когда пользователь покидает документ — это выгодно и для памяти, и для безопасности.
  • Никогда не логируйте и не делитесь токенами; рассматривайте их как краткоживущие учётные данные.

Была ли эта страница полезной?