Я упоминал в своем посте « Добавление входа в социальную сеть в блог Jiwhiz», что функция RememberMe не работает с Spring Social Security. Ну, это потому, что приложение не аутентифицирует пользователя по имени пользователя и паролю, и полностью зависит от социальных сайтов (таких как Google, Facebook и Twitter), чтобы сделать работу. Конфигурация Spring Security по умолчанию не может справиться с этой ситуацией. Spring Security может быть самым сложным программным обеспечением среди всех проектов Spring Portfolio . Для корректной работы очень простого веб-приложения с безопасностью требуется около 10 фильтров. Чтобы упростить разработку приложений, Spring Security предоставляет конфигурацию пространства имен, начиная с версии 2.0, для автоматической настройки всех необходимых компонентов вместе, поэтому разработчикам не нужно разбираться в деталях. Он работает очень хорошо для большинства веб-приложений, если только ваше приложение не отличается от традиционного.
После того, как я изменил процесс входа в систему с аутентификации по имени пользователя на Spring Social Security без пароля, старая конфигурация для запомнить меня больше не работала. В справочном документе Spring Security имеется очень мало объяснений об аутентификации «Помни меня» , поэтому я купил книгу Spring Security 3.1, написанную Робом Уинчем, руководителем проекта Spring Security. В книге есть целая глава, рассказывающая об услугах Remember-Me, и она очень помогла мне понять, как работает функция Remember-Me в Spring Security. После прочтения книги я чувствую, что намного легче читать исходный код Spring Security, а чтение исходного кода всегда доставляет удовольствие.
Поскольку я не храню пароли для учетных записей пользователей, TokenBasedRememberMeServices по умолчанию не может работать с моим приложением, и я не хочу создавать свои собственные RememberMeServices — слишком много работы. К счастью, существует еще один подход к постоянным токенам, который заключается в хранении токенов в базе данных и сравнении токенов в файлах cookie. Все, что мне нужно, это настроить PersistentTokenBasedRememberMeServices в моем приложении с PersistentTokenRepository для хранения токенов. Spring Security предоставляет реализацию PersistentTokenRepository в JDBC, и я обнаружил, что написать собственную реализацию MongoDB после прочтения исходного кода тривиально.
Первым шагом является сохранение данных PersistentRememberMeToken в MongoDB. Мне нужно добавить класс сущности домена для него:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @Document(collection = 'RememberMeToken')publicclassRememberMeToken extendsBaseEntity{    privateString username;    @Indexed    privateString series;    privateString tokenValue;    privateDate date;... // getter/setter omitted    publicRememberMeToken(){    }    publicRememberMeToken(PersistentRememberMeToken token){        this.series = token.getSeries();        this.username = token.getUsername();        this.tokenValue = token.getTokenValue();        this.date = token.getDate();    }} | 
Далее, используйте Spring Data, чтобы добавить хранилище для сущности:
| 1 2 3 4 | publicinterfaceRememberMeTokenRepository extendsMongoRepository<RememberMeToken, String>{    RememberMeToken findBySeries(String series);    List<RememberMeToken> findByUsername(String username);} | 
Тогда единственное относительно тяжелое кодирование — это реализовать PersistentTokenRepository для MongoDB:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | publicclassMongoPersistentTokenRepositoryImpl implementsPersistentTokenRepository {    privatefinalRememberMeTokenRepository rememberMeTokenRepository;    publicMongoPersistentTokenRepositoryImpl(RememberMeTokenRepository rememberMeTokenRepository){        this.rememberMeTokenRepository = rememberMeTokenRepository;    }    @Override    publicvoidcreateNewToken(PersistentRememberMeToken token) {        RememberMeToken newToken = newRememberMeToken(token);        this.rememberMeTokenRepository.save(newToken);    }    @Override    publicvoidupdateToken(String series, String tokenValue, Date lastUsed) {        RememberMeToken token = this.rememberMeTokenRepository.findBySeries(series);        if(token != null){            token.setTokenValue(tokenValue);            token.setDate(lastUsed);            this.rememberMeTokenRepository.save(token);        }    }    @Override    publicPersistentRememberMeToken getTokenForSeries(String seriesId) {        RememberMeToken token = this.rememberMeTokenRepository.findBySeries(seriesId);        returnnewPersistentRememberMeToken(token.getUsername(), token.getSeries(), token.getTokenValue(), token.getDate());    }    @Override    publicvoidremoveUserTokens(String username) {        List<RememberMeToken> tokens = this.rememberMeTokenRepository.findByUsername(username);        this.rememberMeTokenRepository.delete(tokens);    }} | 
Остальная часть работы — вся конфигурация. Мне нужно связать их вместе в классе конфигурации Java:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | @ConfigurationpublicclassSocialAndSecurityConfig {    @Inject    privateEnvironment environment;    @Inject    privateAccountService accountService;    @Inject    privateAuthenticationManager authenticationManager;    @Inject    privateRememberMeTokenRepository rememberMeTokenRepository;...    @Bean    publicRememberMeServices rememberMeServices(){        PersistentTokenBasedRememberMeServices rememberMeServices = newPersistentTokenBasedRememberMeServices(                        environment.getProperty('application.key'), accountService, persistentTokenRepository());        rememberMeServices.setAlwaysRemember(true);        returnrememberMeServices;    }    @Bean    publicRememberMeAuthenticationProvider rememberMeAuthenticationProvider(){        RememberMeAuthenticationProvider rememberMeAuthenticationProvider =                         newRememberMeAuthenticationProvider(environment.getProperty('application.key'));        returnrememberMeAuthenticationProvider;     }    @Bean    publicPersistentTokenRepository persistentTokenRepository() {        returnnewMongoPersistentTokenRepositoryImpl(rememberMeTokenRepository);    }} | 
Последний шаг заключается в добавлении службы запомнить меня в конфигурационный файл безопасности xml, который является последним фрагментом конфигурации XML, и мы не можем сейчас его устранить. (Обновление: новый проект Spring Security Java Config заменит конфигурацию xml на конфигурацию Java в Spring Security.)
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?xmlversion='1.0'encoding='UTF-8'?>    xsi:schemaLocation='        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd'>    <httpuse-expressions='true'entry-point-ref='socialAuthenticationEntryPoint'>        <custom-filterposition='PRE_AUTH_FILTER'ref='socialAuthenticationFilter'/>        <logoutlogout-url='/signout'delete-cookies='JSESSIONID'/>        <remember-meservices-ref='rememberMeServices'/>        <!-- Configure these elements to secure URIs in your application -->        <intercept-urlpattern='/favicon.ico'access='permitAll'/>        <intercept-urlpattern='/robots.txt'access='permitAll'/>        <intercept-urlpattern='/resources/**'access='permitAll'/>        <intercept-urlpattern='/signin'access='permitAll'            requires-channel='#{environment['application.secureChannel']}' />        <intercept-urlpattern='/signin/*'access='permitAll'            requires-channel='#{environment['application.secureChannel']}' />        <intercept-urlpattern='/presentation/**'access='hasRole('ROLE_USER')'            requires-channel='#{environment['application.secureChannel']}' />        <intercept-urlpattern='/myAccount/**'access='hasRole('ROLE_USER')'            requires-channel='#{environment['application.secureChannel']}' />        <intercept-urlpattern='/myPost/**'access='hasRole('ROLE_AUTHOR')'            requires-channel='#{environment['application.secureChannel']}' />        <intercept-urlpattern='/admin/**'access='hasRole('ROLE_ADMIN')'            requires-channel='#{environment['application.secureChannel']}' />        <intercept-urlpattern='/**'access='permitAll'/>    </http>    <authentication-manageralias='authenticationManager'>        <authentication-providerref='socialAuthenticationProvider'/>        <authentication-providerref='rememberMeAuthenticationProvider'/>    </authentication-manager></beans:beans> | 
Это все, что нужно для добавления аутентификации Remember-Me в мое приложение для блога. Теперь вы можете войти через Google / Facebook / Twitter на мой сайт, и сайт будет постоянно помнить вас в течение следующих двух недель.
Ссылка: добавьте аутентификацию RememberMe с помощью Spring Security от нашего партнера по JCG Юаня Цзи в блоге Jiwhiz .