我在“ 将社交登录添加到Jiwhiz博客”中提到,RememberMe功能不适用于Spring Social Security。 好吧,这是因为该应用程序现在不通过用户名和密码对用户进行身份验证,并且完全取决于社交网站(例如Google,Facebook和Twitter)来完成此工作。 默认的Spring Security配置无法处理这种情况。 Spring Security可能是所有Spring Portfolio项目中最复杂的软件。 为了使一个非常简单的Web应用程序具有安全性,大约需要正确设置10个过滤器。 为了简化应用程序开发,Spring Security从2.0版开始提供名称空间配置,以自动将所有必需的组件一起设置,因此开发人员无需弄清楚细节。 除非您的应用程序与传统应用程序不同,否则它对大多数Web应用程序都非常有效。
在将网站登录过程从用户名密码身份验证更改为不带密码的Spring Social Security之后 ,“记住我”的旧配置不再起作用。 Spring Security参考文档几乎没有关于Remember-Me Authentication的解释,所以我买了Spring Security项目负责人Rob Winch编写的书Spring Security 3.1 。 这本书整整一章都在讨论“记住我”服务,它对我在Spring Security中如何理解我的工作很有帮助。 读完本书后,我觉得阅读Spring Security源代码要容易得多,并且阅读源代码总是很有趣的。
由于我没有存储用户帐户的密码,因此默认的TokenBasedRememberMeServices无法与我的应用程序一起使用,并且我也不想创建自己的RememberMeServices-太多的工作。 幸运的是,还有另一种持久令牌方法 ,即将令牌存储到数据库中并比较cookie中的令牌。 我需要的是使用PersistentTokenRepository在我的应用程序中自定义PersistentTokenBasedRememberMeServices来存储令牌。 Spring Security提供了PersistentTokenRepository的JDBC实现,我发现在阅读源代码之后编写自己的MongoDB实现非常简单。
第一步是将PersistentRememberMeToken数据存储到MongoDB。 我需要为其添加一个域实体类:
@Document(collection = 'RememberMeToken')
public class RememberMeToken extends BaseEntity{
private String username;
@Indexed
private String series;
private String tokenValue;
private Date date;
... // getter/setter omitted
public RememberMeToken(){
}
public RememberMeToken(PersistentRememberMeToken token){
this.series = token.getSeries();
this.username = token.getUsername();
this.tokenValue = token.getTokenValue();
this.date = token.getDate();
}
}
接下来,使用Spring Data为实体添加一个存储库:
public interface RememberMeTokenRepository extends MongoRepository<RememberMeToken, String>{
RememberMeToken findBySeries(String series);
List<RememberMeToken> findByUsername(String username);
}
然后,唯一相对繁重的编码是为MongoDB实现PersistentTokenRepository:
public class MongoPersistentTokenRepositoryImpl implements PersistentTokenRepository {
private final RememberMeTokenRepository rememberMeTokenRepository;
public MongoPersistentTokenRepositoryImpl(RememberMeTokenRepository rememberMeTokenRepository){
this.rememberMeTokenRepository = rememberMeTokenRepository;
}
@Override
public void createNewToken(PersistentRememberMeToken token) {
RememberMeToken newToken = new RememberMeToken(token);
this.rememberMeTokenRepository.save(newToken);
}
@Override
public void updateToken(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
public PersistentRememberMeToken getTokenForSeries(String seriesId) {
RememberMeToken token = this.rememberMeTokenRepository.findBySeries(seriesId);
return new PersistentRememberMeToken(token.getUsername(), token.getSeries(), token.getTokenValue(), token.getDate());
}
@Override
public void removeUserTokens(String username) {
List<RememberMeToken> tokens = this.rememberMeTokenRepository.findByUsername(username);
this.rememberMeTokenRepository.delete(tokens);
}
}
剩下的工作就是所有配置。 我需要在Java config类中将它们连接在一起:
@Configuration
public class SocialAndSecurityConfig {
@Inject
private Environment environment;
@Inject
private AccountService accountService;
@Inject
private AuthenticationManager authenticationManager;
@Inject
private RememberMeTokenRepository rememberMeTokenRepository;
...
@Bean
public RememberMeServices rememberMeServices(){
PersistentTokenBasedRememberMeServices rememberMeServices = new PersistentTokenBasedRememberMeServices(
environment.getProperty('application.key'), accountService, persistentTokenRepository());
rememberMeServices.setAlwaysRemember(true);
return rememberMeServices;
}
@Bean
public RememberMeAuthenticationProvider rememberMeAuthenticationProvider(){
RememberMeAuthenticationProvider rememberMeAuthenticationProvider =
new RememberMeAuthenticationProvider(environment.getProperty('application.key'));
return rememberMeAuthenticationProvider;
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
return new MongoPersistentTokenRepositoryImpl(rememberMeTokenRepository);
}
}
最后一步是将“记住我”服务添加到安全性xml配置文件中,这是xml配置的最后一部分,我们现在无法消除它。 (更新:一个新项目Spring Security Java Config将用Spring Security中的Java config替换xml配置。)
<?xml version='1.0' encoding='UTF-8'?>
<beans:beans xmlns='http://www.springframework.org/schema/security'
xmlns:beans='http://www.springframework.org/schema/beans'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
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'>
<http use-expressions='true' entry-point-ref='socialAuthenticationEntryPoint'>
<custom-filter position='PRE_AUTH_FILTER' ref='socialAuthenticationFilter' />
<logout logout-url='/signout' delete-cookies='JSESSIONID' />
<remember-me services-ref='rememberMeServices' />
<!-- Configure these elements to secure URIs in your application -->
<intercept-url pattern='/favicon.ico' access='permitAll' />
<intercept-url pattern='/robots.txt' access='permitAll' />
<intercept-url pattern='/resources/**' access='permitAll' />
<intercept-url pattern='/signin' access='permitAll'
requires-channel='#{environment['application.secureChannel']}' />
<intercept-url pattern='/signin/*' access='permitAll'
requires-channel='#{environment['application.secureChannel']}' />
<intercept-url pattern='/presentation/**' access='hasRole('ROLE_USER')'
requires-channel='#{environment['application.secureChannel']}' />
<intercept-url pattern='/myAccount/**' access='hasRole('ROLE_USER')'
requires-channel='#{environment['application.secureChannel']}' />
<intercept-url pattern='/myPost/**' access='hasRole('ROLE_AUTHOR')'
requires-channel='#{environment['application.secureChannel']}' />
<intercept-url pattern='/admin/**' access='hasRole('ROLE_ADMIN')'
requires-channel='#{environment['application.secureChannel']}' />
<intercept-url pattern='/**' access='permitAll' />
</http>
<authentication-manager alias='authenticationManager'>
<authentication-provider ref='socialAuthenticationProvider' />
<authentication-provider ref='rememberMeAuthenticationProvider' />
</authentication-manager>
</beans:beans>
这就是向我的博客应用程序添加“记住我的身份验证”的全部方法。 现在,您可以通过Google / Facebook / Twitter登录到我的网站,该网站将在接下来的两周内始终记住您。
参考:来自Jiwhiz博客的JCG合作伙伴 Yuan Ji 添加了Spring Security的RememberMe身份验证 。
翻译自: https://www.javacodegeeks.com/2013/03/add-rememberme-authentication-with-spring-security.html