Действительно ли сессии нарушают RESTfulness?

Использование сеансов в RESTful API действительно нарушает RESTfulness? Я видел много мнений, идущих в обоих направлениях, но я не уверен, что сессии проходят без REST. С моей точки зрения:

  • проверка подлинности не запрещена для RESTfulness (в противном случае было бы мало пользы в службах RESTful)
  • аутентификация выполняется путем отправки токена аутентификации в запросе, обычно в заголовке
  • этот токен аутентификации должен быть получен каким-либо образом и может быть отозван, и в этом случае его необходимо обновить
  • маркер аутентификации должен быть проверен сервером (иначе это не будет аутентификация)

Так как сессии нарушают это?

  • на стороне клиента сеансы осуществляются с использованием куки
  • куки - это просто дополнительный HTTP-заголовок
  • сессионный cookie может быть получен и отозван в любое время
  • сеансовые куки могут иметь неограниченное время жизни, если это необходимо
  • идентификатор сеанса (токен аутентификации) проверяется на стороне сервера

Таким образом, для клиента cookie сеанса точно такой же, как и любой другой механизм аутентификации на основе заголовка HTTP, за исключением того, что он использует Cookie заголовок вместо Authorization или какой-то другой фирменный заголовок. Если к серверной части значения cookie не было подключено ни одного сеанса, почему это могло бы изменить ситуацию? Реализация на стороне сервера не должна касаться клиента, пока сервер ведет себя RESTful. Таким образом, куки сами по себе не должны создавать API без REST, а сеансы - это просто куки для клиента.

Мои предположения неверны? Что делает сессионные куки RESTless?

9 ответов

Решение

Сначала давайте определим некоторые термины:

  • RESTful:

    Можно охарактеризовать приложения, соответствующие ограничениям REST, описанным в этом разделе, как "RESTful". [15] Если служба нарушает какое-либо из обязательных ограничений, ее нельзя считать RESTful.

    согласно википедии.

  • ограничение без гражданства:

    Затем мы добавляем ограничение к взаимодействию клиент-сервер: связь должна быть без состояния по своей природе, как в стиле клиент-сервер без состояния (CSS) в разделе 3.4.3 (рисунок 5-3), так что каждый запрос от клиента к Сервер должен содержать всю информацию, необходимую для понимания запроса, и не может использовать какой-либо сохраненный контекст на сервере. Поэтому состояние сеанса полностью сохраняется на клиенте.

    согласно Филдинговой диссертации.

Таким образом, сеансы на стороне сервера нарушают ограничение REST без сохранения состояния и, следовательно, RESTfulness.

Таким образом, для клиента cookie сеанса точно такой же, как и любой другой механизм аутентификации на основе заголовка HTTP, за исключением того, что он использует заголовок Cookie вместо авторизации или какого-либо другого проприетарного заголовка.

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

На мой взгляд, нет ничего плохого в печенье. Технология cookie - это механизм хранения на стороне клиента, в котором хранимые данные автоматически присоединяются к заголовкам cookie при каждом запросе. Я не знаю ограничения REST, которое имеет проблемы с такими технологиями. Так что с самой технологией проблем нет, проблема с ее использованием. Филдинг написал подраздел о том, почему он считает, что HTTP-куки - это плохо.

С моей точки зрения:

  • проверка подлинности не запрещена для RESTfulness (в противном случае было бы мало пользы в службах RESTful)
  • аутентификация выполняется путем отправки токена аутентификации в запросе, обычно в заголовке
  • этот токен аутентификации должен быть получен каким-либо образом и может быть отозван, и в этом случае его необходимо обновить
  • маркер аутентификации должен быть проверен сервером (иначе это не будет аутентификация)

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

Рисунок 1. - Аутентификация без сохранения состояния доверенными клиентами

  • Рисунок 1. - Аутентификация без сохранения состояния доверенными клиентами

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

Теперь это работает довольно хорошо доверенными клиентами, написанными вами, но как насчет сторонних клиентов? Они не могут иметь имя пользователя и пароль, а также все разрешения пользователей. Таким образом, вы должны отдельно хранить разрешения, которые может иметь сторонний клиент для конкретного пользователя. Таким образом, разработчики клиентов могут зарегистрировать своих сторонних клиентов и получить уникальный ключ API, а пользователи могут разрешить сторонним клиентам получать доступ к некоторой части своих разрешений. Например, чтение имени и адреса электронной почты, перечисление их друзей и т. Д. После разрешения стороннего клиента сервер сгенерирует токен доступа. Эти токены доступа могут использоваться сторонним клиентом для доступа к разрешениям, предоставленным пользователем, например:

Рисунок 2. - Аутентификация без сохранения состояния сторонними клиентами

  • Рисунок 2. - Аутентификация без сохранения состояния сторонними клиентами

Таким образом, сторонний клиент может получить токен доступа от доверенного клиента (или напрямую от пользователя). После этого он может отправить действительный запрос с ключом API и токеном доступа. Это самый основной сторонний механизм аутентификации. Вы можете прочитать больше о деталях реализации в документации каждой сторонней системы аутентификации, например, OAuth. Конечно, это может быть более сложным и более безопасным, например, вы можете подписать детали каждого отдельного запроса на стороне сервера и отправить подпись вместе с запросом и т. Д. Фактическое решение зависит от потребностей вашего приложения.

Прежде всего, REST не является религией и не должен рассматриваться как таковой. Хотя у сервисов RESTful есть свои преимущества, вы должны следовать принципам REST только в той мере, в которой они имеют смысл для вашего приложения.

При этом аутентификация и состояние на стороне клиента не нарушают принципы REST. В то время как REST требует, чтобы переходы состояний были без сохранения состояния, это относится к самому серверу. В основе всего REST лежит документация. Идея безгражданства заключается в том, что СЕРВЕР - это не клиент, а не клиент. Любой клиент, отправляющий идентичный запрос (те же заголовки, файлы cookie, URI и т. Д.), Должен быть перенесен в одно и то же место в приложении. Если веб-сайт сохранил текущее местоположение пользователя и управлял навигацией, обновив эту переменную навигации на стороне сервера, тогда REST будет нарушен. Другой клиент с идентичной информацией запроса будет доставлен в другое место в зависимости от состояния на стороне сервера.

Веб-сервисы Google являются фантастическим примером системы RESTful. Они требуют, чтобы заголовок аутентификации с ключом аутентификации пользователя передавался при каждом запросе. Это немного нарушает принципы REST, поскольку сервер отслеживает состояние ключа аутентификации. Состояние этого ключа должно поддерживаться, и у него есть какая-то дата / время истечения срока действия, после которого он больше не предоставляет доступ. Однако, как я уже упоминал в начале своего поста, жертвы должны быть принесены, чтобы приложение действительно работало. При этом токены аутентификации должны храниться таким образом, чтобы все возможные клиенты продолжали предоставлять доступ в течение их действительного времени. Если один сервер управляет состоянием ключа аутентификации до такой степени, что другой сервер с балансировкой нагрузки не может принять выполненные запросы на основе этого ключа, вы начали действительно нарушать принципы REST. Службы Google гарантируют, что вы в любой момент сможете взять токен аутентификации, который вы использовали на своем телефоне, с сервером А для балансировки нагрузки, а также с сервера Б для балансировки нагрузки со своего рабочего стола, и при этом иметь доступ к системе и быть направленным на те же ресурсы, если запросы были идентичны.

Все это сводится к тому, что вам нужно убедиться, что ваши токены аутентификации проверены в каком-либо резервном хранилище (база данных, кеш и т. Д.), Чтобы обеспечить сохранение как можно большего количества свойств REST.

Я надеюсь, что все это имело смысл. Вам также следует ознакомиться с разделом "Ограничения" статьи в Википедии о передаче представительского состояния, если вы этого еще не сделали. Это особенно поучительно в отношении того, о чем на самом деле спорят принципы REST и почему.

Cookies не для аутентификации. Зачем изобретать велосипед? HTTP имеет хорошо разработанные механизмы аутентификации. Если мы используем файлы cookie, мы используем HTTP только в качестве транспортного протокола, поэтому нам нужно создать собственную систему сигнализации, например, чтобы сообщать пользователям, что они предоставили неверную аутентификацию (использование HTTP 401 было бы неправильным, поскольку мы, вероятно, не будем поставка Www-Authenticate клиенту, как того требуют спецификации HTTP:)). Следует также отметить, что Set-Cookie это только рекомендация для клиента. Его содержимое может быть сохранено или не сохранено (например, если файлы cookie отключены), а Authorization заголовок отправляется автоматически при каждом запросе.

Другой момент заключается в том, что для получения авторизационного куки вы, вероятно, захотите сначала указать свои учетные данные? Если это так, то не будет ли это без RESTless? Простой пример:

  • Вы пытаетесь GET /a без печенья
  • Вы получаете запрос авторизации как-то
  • Вы идете и авторизуетесь как-то POST /auth
  • Ты получаешь Set-Cookie
  • Вы пытаетесь GET /a с печеньем Но делает GET /a вести себя идемпотентно в этом случае?

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

На самом деле, RESTfulness применяется только к RESOURCES, как указано универсальным идентификатором ресурса. Поэтому даже говорить о таких вещах, как заголовки, файлы cookie и т. Д. В отношении REST, не совсем уместно. REST может работать по любому протоколу, даже если он обычно выполняется по HTTP.

Основным определителем является следующее: если вы отправляете вызов REST, который является URI, то после успешного вызова на сервер этот URI возвращает тот же контент, предполагая, что переходы не были выполнены (PUT, POST, DELETE)? Этот тест исключил бы ошибки или запросы на аутентификацию, которые возвращаются, потому что в этом случае запрос еще не поступил на сервер, то есть сервлет или приложение, которое будет возвращать документ, соответствующий данному URI.

Аналогично, в случае POST или PUT, можете ли вы отправить определенный URI/ полезную нагрузку, и независимо от того, сколько раз вы отправляете сообщение, оно всегда будет обновлять одни и те же данные, чтобы последующие GET возвращали согласованный результат?

REST относится к данным приложения, а не к низкоуровневой информации, необходимой для передачи этих данных.

В следующем сообщении в блоге Рой Филдинг дал хорошее резюме всей идеи REST:

http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/5841

"Система RESTful переходит от одного устойчивого состояния к следующему, и каждое такое устойчивое состояние является как потенциальным начальным состоянием, так и потенциальным конечным состоянием. То есть система RESTful представляет собой неизвестное число компонентов, подчиняющихся простому набору правила такие, что они всегда находятся в состоянии REST или переходят из одного состояния RESTful в другое состояние RESTful. Каждое состояние может быть полностью понято представлением (ями), которое оно содержит, и набором переходов, которые оно обеспечивает, с переходами, ограниченными униформой набор действий, которые должны быть понятны. Система может представлять собой сложную диаграмму состояний, но каждый пользовательский агент может видеть только одно состояние за раз (текущее устойчивое состояние), и, таким образом, каждое состояние является простым и может анализироваться независимо. Пользователь OTOH может создавать свои собственные переходы в любое время (например, ввести URL-адрес, выбрать закладку, открыть редактор и т. д.)."


Переходя к вопросу аутентификации, независимо от того, выполняется ли она с помощью файлов cookie или заголовков, если информация не является частью полезной нагрузки URI и POST, она на самом деле не имеет ничего общего с REST. Итак, что касается отсутствия статуса, мы говорим только о данных приложения.

Например, когда пользователь вводит данные в экран графического интерфейса, клиент отслеживает, какие поля были введены, а какие нет, какие-либо обязательные поля пропущены и т. Д. Это все КЛИЕНТСКИЙ КОНТЕКСТ, и его не следует отправлять или отслеживать на сервере. На сервер отправляется полный набор полей, которые необходимо изменить в ресурсе IDENTIFIED (посредством URI), чтобы в этом ресурсе происходил переход из одного состояния RESTful в другое.

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

Насколько я понимаю, есть два типа состояния, когда мы говорим о сессиях

  • Состояние взаимодействия клиента и сервера
  • Состояние ресурса

Ограничение без сохранения состояния здесь относится ко второму типу в Rest. Использование файлов cookie (или локального хранилища) не нарушает Rest, поскольку оно связано с первым.

Филдинг говорит: «Каждый запрос от клиента к серверу должен содержать всю информацию, необходимую для понимания запроса, и не может использовать какой-либо сохраненный на сервере контекст. Таким образом, состояние сеанса полностью сохраняется на клиенте».

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

Транзакция HTTP, базовая аутентификация доступа, не подходит для RBAC, потому что базовая аутентификация доступа использует каждый раз для идентификации зашифрованное имя пользователя: пароль, а в RBAC необходима роль, которую пользователь хочет использовать для определенного вызова. RBAC не проверяет разрешения для имени пользователя, но для ролей.

Вы могли бы обойтись без конкатенации следующим образом: usernameRole:password, но это плохая практика, и это также неэффективно, потому что, когда у пользователя больше ролей, механизму аутентификации потребуется проверять все роли в конкатенации и повторять каждый вызов. Это уничтожило бы одно из самых больших технических преимуществ RBAC, а именно очень быстрый тест авторизации.

Так что эта проблема не может быть решена с помощью обычной аутентификации доступа.

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

Это то, что мне нравится в ответе, что REST не следует рассматривать как религию. Например, в сложных бизнес-ситуациях, например, в здравоохранении, RBAC абсолютно обычен и необходим. И было бы жаль, если бы им не разрешили использовать REST, потому что все разработчики REST-инструментов рассматривали бы REST как религию.

Для меня не так много способов поддерживать сеанс через HTTP. Можно использовать куки с sessionId или заголовок с sessionId.

Если у кого-то есть другая идея, я буду рад ее услышать.

Я думаю, что токен должен включать всю необходимую информацию, закодированную внутри него, что делает аутентификацию путем проверки токена и декодирования информации https://www.oauth.com/oauth2-servers/access-tokens/self-encoded-access-tokens/

Нет, использование сеансов не обязательно нарушает RESTfulness. Если вы придерживаетесь правил и ограничений REST, то использование сеансов для поддержания состояния будет просто излишним. В конце концов, RESTfulness требует, чтобы сервер не поддерживал состояние.

  1. Сессии не без отдыха
  2. Вы имеете в виду, что сервис REST только для http-использования или я что-то не так понял? Сеанс на основе файлов cookie должен использоваться только для собственных (!) Служб на основе http! (Это может быть проблемой для работы с cookie, например, из Mobile / Console / Desktop / etc.)
  3. если вы предоставляете сервис RESTful для сторонних разработчиков, никогда не используйте сеанс на основе файлов cookie, вместо этого используйте токены, чтобы избежать проблем с безопасностью.
Другие вопросы по тегам