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

Автентифікація за методом 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, яка зберігає токени в базі даних>