В нашем приложении есть рабочий процесс аутентификации / авторизации JWT. Пользователь входит в систему, интерфейсное приложение получает токен JWT в качестве ответа при успешном входе в систему, сохраняет его в локальном хранилище и использует его для выполнения вызовов api к api остатка серверной части, отправляя его в заголовке Authorization. Все было хорошо, пока мы не поняли, что изображения (или другие статические ресурсы) за аутентификацией не работают из коробки.

Это почему? Поскольку запрос этих статических ресурсов генерируется непосредственно браузером, а веб-приложение не имеет возможности добавить заголовок Authorization к этим запросам, поскольку эти запросы не инициируются изнутри веб-приложения (что означает, что они не могут быть перехвачены или изменен приложением).

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

Фундаментальные исследования побудили нас рассмотреть следующие варианты:

  1. Подписанные URL-адреса на стороне сервера: URL-адреса подписаны на стороне сервера с помощью токена, который невозможно угадать, и доступны на неаутентифицированной конечной точке до тех пор, пока сервер не истечет. Пользовательский интерфейс получит эти URL-адреса, и браузер сможет выполнять вызовы для получения изображения как обычно. Проблема заключается в том, что конечная точка не аутентифицирована, и если URL-адрес перенаправляется другому пользователю, у них также будет доступ к изображению, если они получат изображение до истечения срока действия токена на стороне сервера.
  2. Подписанные URL-адреса со стороны клиента: URL-адреса с токеном, отправленным в параметрах запроса.
    Поскольку у нас уже есть JWT для пользователя, мы могли бы добавить его к URL-адресу изображения, и сервер может проверить его с помощью вызова браузера . Это означает, что фактический пользовательский JWT отображается в параметрах запроса, что является опасным делом.
    Или мы могли бы сделать отдельный вызов браузера, чтобы получить конкретный JWT для изображения и добавить его к URL-адресу изображения, когда он время для браузера, чтобы получить изображение. Это потребует принятия некоторых решений или синхронизации на интерфейсе, когда нужно сделать вызов, чтобы получить токен и добавить его к URL-адресу изображения до того, как браузер сделает запрос. В этом случае также имеет смысл иметь токены с коротким сроком действия, так что даже если пользователь пересылает этот URL кому-то, токен больше не действителен.
  3. Получите изображения в приложении как responseType: blob, создайте на его основе URL-адрес большого двоичного объекта и привяжите его к img src во время выполнения, это позволяет нам обрабатывать запросы GET изображения как любые другие запросы, и мы можем отправлять заголовок Authorization. Это не требует каких-либо изменений на сервере для подписи URL-адресов или для получения токена из параметров запроса.
  4. Мы могли бы хранить информацию аутентификации в файлах cookie, и, поскольку файлы cookie по умолчанию могут отправляться в запросах браузера, сервер может просто проверять информацию аутентификации из файла cookie. В нашей настройке есть 2 проблемы с этим подходом: во-первых, у нас уже есть поток аутентификации jwt на основе localstorage, а во-вторых, api работает в другом домене, и нам нужно будет обрабатывать файлы cookie междоменного доступа, которые могут иметь само по себе было огромным усилием.

Мы пошли дальше с третьим подходом: получить изображение как blob и привязать его к image src. Это помогло нам в быстрой разработке, так как мы не вносили никаких изменений на сервере для создания подписанных URL-адресов, и мы чувствовали, что это более безопасно, потому что URL-адрес никогда не будет содержать токен, поэтому, даже если он будет передан, нам не придется иметь дело с проверкой короткого срока действия токена.

Однако с этим есть проблема. Это отлично работает для отображения изображений в приложении, но что произойдет, когда мы позволим пользователю загружать эти изображения? Обычно требуется открыть URL-адрес изображения в новой вкладке браузера, и браузер позаботится о загрузке файла после его получения. В нашем случае это не сработает, поскольку вызов из новой вкладки не будет содержать информацию об авторизации в заголовке, и загрузка не удастся. Для этого нам, вероятно, потребуется перейти к решению на основе подписанного URL-адреса.

Использованная литература: