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