Краткое описание
Аутентификация по методу Remember-me или persistent-login относится к веб-узлам, которые могут запоминать личность пользователя между сессиями. Обычно это достигается путем отправки cookie в браузер, при этом cookie обнаруживается во время последующих сессий и приводит к автоматическому входу в систему. Spring Security предусматривает необходимые перехватчики для выполнения этих операций и имеет две конкретные реализации remember-me. Одна из них использует хэширование для поддержания безопасности токенов на основе cookie, а другая использует базу данных или иной механизм постоянного хранения для хранения сгенерированных токенов.
Обратите внимание, что для обеих реализаций требуется UserDetailsService
. Если вы используете поставщика аутентификации, который не использует UserDetailsService
(например, поставщик LDAP), то он не будет работать, если в контексте приложения также не будет бина UserDetailsService
.
Простой подход с использованием токенов на основе хэша
Этот подход использует хэширование для успешного выполнения полезной стратегии remember-me. По сути, cookie отправляется в браузер после успешной интерактивной аутентификации, при этом cookie состоит из следующих элементов:
base64(username + ":" + expirationTime + ":" +
md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
username: Который сможет определить UserDetailsService
password: Совпадает с тем, который содержится в полученных UserDetails
expirationTime: Дата и время истечения срока действия токена remember-me, выраженные в миллисекундах
key: Закрытый ключ для предотвращения изменения токена remember-me
Таким образом, токен remember-me действителен только в течение указанного периода и при условии, что имя пользователя, пароль и ключ не меняются. Примечательно, что в этом случае возникает потенциальная проблема в отношении безопасности, так как полученный токен remember-me будет доступен для использования с любого пользовательского агента до тех пор, пока срок действия токена не истечет. Это та же проблема, что и в случае с дайджест-аутентификацией. Если принципал знает, что токен был перехвачен, он может легко изменить свой пароль и немедленно аннулировать все выданные токены remember-me. Если требуется более серьезная защита, следует использовать подход, описанный в следующем разделе. Или же сервисы remember-me не следует использовать вообще.
Если вы знакомы с темами, рассмотренными в главе, посвященной конфигурации пространства имен, то можете активировать аутентификацию remember-me, просто добавив элемент <remember-me>
:
<http>
...
<remember-me key="myAppKey"/>
</http>
Конкретная UserDetailsService
обычно выбирается автоматически. Если в вашем контексте приложения их несколько, то необходимо задать, какой из них следует использовать, с помощью атрибута user-service-ref
, где значением является имя вашего бина для UserDetailsService
.
Подход, основанный на использовании постоянных токенов
Данный подход основан на статье http://jaspan.com/improved_persistent_login_cookie_best_practice с некоторыми незначительными изменениями [1]. Чтобы использовать этот подход с конфигурацией пространства имен, нужно предоставить ссылку на datasource:
<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>
База данных должна содержать таблицу persistent_logins
, созданную с помощью следующего SQL (или эквивалентного):
create table persistent_logins (username varchar(64) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null)
Интерфейсы и реализации метода Remember-Me
Метод Remember-me используется с UsernamePasswordAuthenticationFilter
и реализуется с помощью перехватчиков в суперклассе AbstractAuthenticationProcessingFilter
. Он также используется в BasicAuthenticationFilter
. Перехватчики будут вызывать конкретные RememberMeServices
в соответствующие моменты времени. Интерфейс выглядит следующим образом:
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
void loginFail(HttpServletRequest request, HttpServletResponse response);
void loginSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication successfulAuthentication);
Пожалуйста, обратитесь к Javadoc, чтобы ознакомиться с более полным описанием принципов работы этих методов, хотя на данном этапе обратите внимание, что AbstractAuthenticationProcessingFilter
вызывает только методы loginFail()
и loginSuccess()
. Метод autoLogin()
вызывается RememberMeAuthenticationFilter
всякий раз, если SecurityContextHolder
не содержит Authentication
. Поэтому этот интерфейс обеспечивает базовую реализацию remember-me с надлежащим уведомлением о событиях, связанных с аутентификацией, и делегирует ей полномочия в тех случаях, когда веб-запрос кандидата может содержать cookie и его необходимо запомнить. Такая структура позволяет использовать любое количество стратегий реализации remember-me. Выше мы узнали, что Spring Security предусматривает две реализации. Мы рассмотрим их по очереди.
TokenBasedRememberMeServices
TokenBasedRememberMeServices
генерирует RememberMeAuthenticationToken
, который обрабатывается RememberMeAuthenticationProvider
. Экземпляр key
совместно используется этим поставщиком аутентификации и TokenBasedRememberMeServices
. Кроме того, TokenBasedRememberMeServices
требует экземпляр UserDetailsService, из которого он сможет получить имя пользователя и пароль для сопоставления подписи, а также сгенерировать RememberMeAuthenticationToken
, чтобы он содержал правильные GrantedAuthority
. Приложение должно предусматривать какую-то команду выхода из системы, которая аннулирует cookie, если пользователь сделает соответствующий запрос. TokenBasedRememberMeServices
также реализует интерфейс LogoutHandler
из Spring Security, поэтому может использоваться вместе с LogoutFilter
для автоматической очистки cookie.
Ниже перечислены бины, которые обязательно должны находиться в контексте приложения, чтобы можно было активировать сервисы remember-me:
<bean id="rememberMeFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>
<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>
Не забудьте добавить реализацию RememberMeServices
в свойство UsernamePasswordAuthenticationFilter.setRememberMeServices()
, добавить RememberMeAuthenticationProvider
в список AuthenticationManager.setProviders()
и добавить RememberMeAuthenticationFilter
в FilterChainProxy
(обычно сразу после UsernamePasswordAuthenticationFilter
).
PersistentTokenBasedRememberMeServices
Этот класс можно использовать так же, как и TokenBasedRememberMeServices
, но дополнительно необходимо добавить в конфигурацию PersistentTokenRepository
для хранения токенов. Существует две стандартные реализации.
-
InMemoryTokenRepositoryImpl
, которая предназначен только для тестирования. -
JdbcTokenRepositoryImpl
, которая хранит токены в базе данных>
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ