Короткий опис

Автентифікація за методом 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, щоб він містив правильні GrantedAut. Програма повинна передбачати якусь команду виходу із системи, яка анулює 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 до списку Authen і додати RememberMeAuthenticationFilter до FilterChainProxy (зазвичай відразу після UsernamePasswordAuthenticationFilter).

PersistentTokenBasedRememberMeServices

Цей клас можна використовувати так само, як і TokenBasedRememberMeServices, але додатково необхідно додати конфігурацію PersistentTokenRepository для зберігання токенів. Існують дві стандартні реалізації.

  • InMemoryTokenRepositoryImpl, яка призначена лише для тестування.

  • JdbcTokenRepositoryImpl, яка зберігає токени в базі даних>