Повторный вызов на истекший сеанс: ответ HTTP 401 заставляет браузер отображать окно входа в систему

Я написал приложение HTML 5, которое использует AngularJS и интерфейсы с бэкэндом Java REST, работающим на Tomcat. Я использую Spring Security для обработки логина и безопасности.

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

Проблема, с которой я столкнулся, - это время окончания сеанса. Это вызывает ответ HTTP 401 Unauthenticated с сервера. Я думал, что смогу поймать эту ошибку и перенаправить пользователя обратно на страницу входа с Javascript. Однако до того, как вызывается мой обработчик ошибок, браузер сначала показывает окно входа в систему, только если я нажму "Отменить мой обработчик ошибок Javascript", вы сможете обработать ответ.

Мой вопрос в том, есть ли способ предотвратить отображение браузером этого окна входа в систему? Или это общая проблема с моим дизайном приложения?

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

Ниже приведен ответ HTTP с сервера:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
WWW-Authenticate: Basic realm="Spring Security Application"
Content-Type: text/html;charset=utf-8
Content-Length: 999
Date: Mon, 30 Sep 2013 11:00:34 GMT

Обновление: Похоже, что причиной этого является заголовок WWW-Authenticate, который заставляет браузер отображать диалоговое окно входа в систему.

Ответ 1

Наконец, я нашел решение для этого. Как я упоминал в своем обновлении, причина в том, что ответ содержит поле заголовка WWW-Authenticate. Моим решением было изменить конфигурацию безопасности spring, чтобы вернуть другой заголовок:

WWW-Authenticate: FormBased

Для этого мне пришлось реализовать интерфейс AuthenticaitonEntryPoint и вручную задать заголовок и код состояния в ответе:

@Component( "restAuthenticationEntryPoint" )
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence( HttpServletRequest request, HttpServletResponse response,
                          AuthenticationException authException ) throws IOException {
        response.setHeader("WWW-Authenticate", "FormBased");
        response.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
    }
}

то я изменил конфигурацию spring -security и установил entry-point-ref для указания на новый класс:

<http pattern="/rest/**" create-session="never" entry-point-ref="restAuthenticationEntryPoint">
    <intercept-url pattern="/rest/**" access="ROLE_USER" />
    <http-basic />
    <session-management />
</http>

Ответ 2

Если вы хотите избежать изменения сервера и заставить его возвращать заголовок WWW-Authenticate для всех других вызывающих абонентов, вы можете изменить свой клиент для отправки своего запроса с заголовком X-Requested-With с XMLHttpRequest значением. По умолчанию Spring Security не отправит WWW-Authenticate для таких запросов. (см. Spring источник)