(я понимаю, что этот вопрос старый, но это то, на что другие люди хотели бы получить ответ)
ОСНОВНАЯ Аутентификация на самом деле не позволяет получить то, о чем вы просите, но вы можете получить что-то, что работает, как то, что вы хотите, если вы готовы жить с некоторыми "причудами".
ОСНОВНАЯ Аутентификация имеет 2 аспекта, которые затрудняют управление этим способом
- без гражданства
- Это на стороне клиента
Оба эти аспекта являются функциями, но они затрудняют привязку аутентификации BASIC к сеансам Java. Вот почему существуют альтернативные механизмы входа в систему (например, вход в Java FORM)
ОСНОВНАЯ Аутентификация без сохранения состояния
Это означает, что клиент не имеет абсолютно никакого представления о том, что происходит на стороне сервера, и у него, безусловно, нет способа связать набор учетных данных BASIC Authentication с файлом cookie (что в основном контролирует сеанс Java)
Что происходит в том случае, если браузер будет просто отправлять имя пользователя + пароль с каждым запросом, пока не решит прекратить работу (как правило, потому что браузер был закрыт и был создан новый сеанс браузера).
Браузер не знает, что сервер делает с учетными данными. Он не знает, нужны ли они больше или нет, и не знает, когда серверная сторона решила, что «новый сеанс» запущен, он просто продолжает отправлять это имя пользователя + пароль с каждым запросом.
ОСНОВНАЯ Аутентификация на стороне клиента
Этот диалог для пользователя / пароля обрабатывается клиентом. Все, что говорит сервер: «Запрошенному URL-адресу требуется имя пользователя + пароль, и мы назвали эту область безопасности« xyz »».
Сервер не знает, вводит ли пользователь пароль каждый раз, или клиент их кеширует. Он не знает, действительно ли там есть пользователь или пароль был извлечен из файла.
Единственное, что может сделать сервер, это сказать: «Вы должны дать мне имя пользователя и пароль перед доступом к этому URL»
Как подделать
По сути, вам необходимо определить (то есть сделать обоснованное предположение), когда браузер отправляет старые учетные данные, а затем снова отправить ответ «Пожалуйста, дайте мне пароль и пароль» (HTTP 401).
Самый простой способ сделать это - использовать в приложении фильтр, который обнаруживает первый раз, когда пользователь вошел в систему для этого сеанса, и отправляет код ответа 401
. Что-то вроде:
if(session.getAttribute("auth") == null)
{
response.setStatus(401);
response.setHeader("WWW-Authenticate", "basic realm=\"Auth (" + session.getCreationTime() + ")\"" );
session.setAttribute("auth", Boolean.TRUE);
writer.println("Login Required");
return;
}
В этом примере я назвал область с временем создания сеанса (хотя это не очень красиво - вы, вероятно, захотите отформатировать его по-другому). Это означает, что имя области безопасности меняется каждый раз, когда вы аннулируете сеанс, что помогает избежать путаницы в клиенте (почему он снова запрашивает у меня пароль пользователя + для той же области, когда я только что его дал?) .
Новое имя области не будет сбивать с толку контейнер сервлета, потому что оно никогда его не увидит - ответ клиента не включает имя области.
Однако хитрость заключается в том, что вы не хотите, чтобы у пользователя дважды запрашивали его пароль при первом входе в систему. И из коробки это решение сделает это - один раз, когда контейнер попросит об этом, а затем снова, когда ваш фильтр сделает.
Как не получить 2 поля для входа
Есть 4 варианта.
- Сделайте все это в коде.
- Используйте дополнительный файл cookie сеанса, чтобы попытаться определить, входит ли пользователь в первый раз.
- Пусть ваш корневой URL не защищен (но ничего не делает)
- Пусть все ваше приложение будет незащищенным, кроме 1 страницы, и перенаправит пользователей на эту страницу, если они не вошли в систему.
Сделайте это в коде
Если вы счастливы сделать все меры безопасности внутри своего собственного сервлета / фильтра и не получите помощи от контейнера сервлета (Jetty), то это не так уж сложно. Вы просто отключаете BASIC auth в своем файле web.xml и делаете все это в коде. (Работы довольно много, и вам нужно убедиться, что вы не оставляете дыр в безопасности открытыми, но это концептуально довольно просто)
Большинство людей не хотят этого делать.
Вторичное печенье
После того, как пользователь войдет в ваше приложение, вы можете установить cookie («аутентифицированный»), срок действия которого истекает в конце сеанса браузера. Этот файл cookie привязан к сеансу браузера, а не к сеансу Java.
При аннулировании сеанса Java - не не делает недействительным «аутентифицированный» cookie.
Если пользователь входит в свежий сеанс Java (т. Е. session.getAttribute("auth")==null
), но все еще имеет этот «аутентифицированный» , то вы знаете, что он повторно использует существующий сеанс браузера вероятно повторно использует существующие учетные данные HTTP-аутентификации.
В этом случае вы делаете трюк 401
, чтобы заставить их выдавать новые учетные данные.
незащищенный корневой URL
Если ваш корневой URL-адрес небезопасен, и вы знаете, что это тот URL-адрес, по которому ваши пользователи всегда входят в систему, вы можете просто поставить проверку «auth» / 401
на этот URL-адрес, и это решит проблему.
Но убедитесь, что вы случайно не открыли дыру в безопасности.
Этот URL не должен иметь никаких функций, кроме перенаправления пользователей в «реальное» приложение (которое защищено)
Один защищенный URL
Имейте 1 защищенный URL (например, "/login").
Как и ваш фильтр «auth» / 401
, на всех страницах (кроме входа в систему) есть другой фильтр (или дополнительный код в том же фильтре), который проверяет, установлен ли request.getUserPrincipal()
. Если нет, перенаправьте пользователя на "/login".
намного более простое решение
Просто используйте метод входа в систему FORM вместо базовой аутентификации. Он предназначен для решения этой проблемы.