Spring security - невозможно выйти - PullRequest
14 голосов
/ 17 февраля 2011

Я модифицировал свое приложение GWT / GXT с базовой авторизацией LDAP с использованием базовой аутентификации HTTP.Он хорошо работает, когда я запускаю новый браузер - я получаю приглашение и авторизируюсь по корпоративному LDAP.Моя проблема - я не могу выйти из системы, пока я не закрою / снова не открою браузер.Я могу отладить и посмотреть, как вызывается SecurityContextLogoutHandler#logout, и выполняется следующий код

    if (invalidateHttpSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
        }
    }

    SecurityContextHolder.clearContext();

Однако, по-видимому, это не имеет никакого эффекта, поскольку сайт перезагружается, и я никогда не получаю другое приглашение HTTP-аутентификации, пока я не перезапущу браузердаже очистка кеша / куки не поможет).Вот соответствующая часть applicationContext.xml

<security:http auto-config='true'>
    <security:intercept-url pattern="/reports/**" access="ROLE_USER" />
    <security:http-basic />
    <security:logout logout-url="/reports/logout" 
              logout-success-url="/reports/Application.html" />       
</security:http>

Я пытался определить пользовательский LogoutSuccessHandler и сделать authentication.setAuthenticated(false);, но это также не имеет никакого эффекта

Что-то здесь, что мне здесь не хватает?Ваша помощь будет высоко ценится

Ответы [ 6 ]

25 голосов
/ 17 февраля 2011

OK.потратив слишком много времени на это, я думаю, что у меня есть ответ.Все просто - нельзя выручить простую аутентификацию HTTP, используя технологию на стороне сервера.По сути, строка авторизации декодируется в base-64 в заголовке HTTP, и когда защищенная страница загружается в браузер, токен безопасности заполняется заново, поэтому независимо от того, как часто вы стираете его на сервере, он воскресает при каждом вызове страницы.Я полагаю, что можно выполнить некоторые хитрые трюки на стороне браузера, но это было бы хрупко и ненадежно

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

Я буду продолжать принимать собственный ответ в пользу кого-то, кто предложит приемлемое решение

4 голосов
/ 04 июля 2012

Бостон в основном прав, что вы не можете справиться с этой серверной стороной.Однако есть немного хака, доступного .

Краткий ответ - перенаправить пользователя на URL, на который вы хотите, чтобы он попал, но добавьте к нему неправильное имя пользователязатем @.Так что в качестве уродливого примера:

<security:logout logout-url="/reports/logout" 
    logout-success-url="http://BADNAME@localhost/reports/Application.html" />

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

3 голосов
/ 17 февраля 2011

Хм ... странно. Я не вижу ничего плохого в вашей конфигурации. Вам действительно не нужно определять какой-либо пользовательский обработчик выхода из системы, потому что он должен обрабатываться Spring Security.

Попробуйте вместо того, чтобы определить logout-url, используйте ссылку выхода по умолчанию: -

...
<security:logout logout-success-url="/reports/Application.html" />      
...

Затем используйте /j_spring_security_logout для выхода.

Это работает вообще?

0 голосов
/ 27 сентября 2016

Один из способов сделать это - вернуть ответы HTTP 401. Некоторое быстрое тестирование показывает, что это работает в MacOS-версиях Safari, Chrome и Firefox. Код, который я использую, по сути эквивалентен этому:

@RequestMapping(value="/logout",method=RequestMethod.POST)
public void logout(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
    session.setAttribute(LOGOUT_SESSION_KEY, true);
    response.setStatus(303);
    response.addHeader("Location", URL_OF_APPLICATION_HOME_PAGE);
}

@RequestMapping("/")
public void home(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
    if (Boolean.TRUE.equals(session.getAttribute(LOGOUT_SESSION_KEY))) {
        if (request.getHeader("Authorization") != null) {
            session.invalidate();
        }

        response.setStatus(401);
        response.addHeader("WWW-Authenticate", "Basic realm=\"" + HTTP_BASIC_REALM + "\"");
        return;
    }

    /* Generate home page */
}

Хитрость в том, что вам обычно нужно возвращать заголовок 401 дважды - после первого браузер повторяет попытку с использованием своих кэшированных учетных данных (отправляя заголовок «Авторизация», после чего мы уничтожаем старый сеанс пользователя) второй, кажется, очищает их и запрашивает логин.

0 голосов
/ 28 марта 2012

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

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

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

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

0 голосов
/ 17 февраля 2011
<logout invalidate-session="true" logout-url="/reports/logout"
        logout-success-url="/reports/Application.html" />

просто установите недействительный сеанс в 'true' и посмотрите, работает ли он.

проверьте, есть ли этот список в вашем web.xml:

<!-- Security: to listen session requests -->
<listener>
     <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
 </listener>

Если все вышеперечисленноене работают, то вы можете попробовать следующее решение.Я думаю, проблема в следующей строке:

<security:intercept-url pattern="/reports/**" access="ROLE_USER" />

Над строкой означает, что вы добавили доступ ROLE_USER к ссылке '/ reports / **'.Но после выхода из системы вы даете тот же URL для успешного выхода из системы.тогда как это будет работать?Либо измените местоположение своей страницы успешного выхода из системы, либо добавьте следующую строку в тег http.

<intercept-url pattern="/reports/Application.html" filters="none" />
...