使用Spring Security添加RememberMe身份验证

我在“ 将社交登录添加到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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值