漫步SpringSecurity---采用持久化token来实现remember-me功能(SpringBoot项目)

之前几篇博客记录了一下SpringSecurity一些基础知识,也在整合Security那篇博客中记录了remember-me的使用方法和一些基本原理。这一篇就来记录一个和remember-me有关的一个操作,采用持久化token的方式来实现remember-me


本次记录是在原有代码上改动(实现好普通remember-me)功能的代码

小前言

以前我们实现remember-me功能时,是直接在配置类相应方法中加入这一行代码:

		http.rememberMe();

之后就会在登录页面自动生成这一个单选框。
在这里插入图片描述
当然如果我们需要自定义登录页的话,只需要在前端页面添加一个radio的单选框,name为remember-me,value为true即可

问题剖析

上述的实现原理大致是用户勾选该单选框之后,Security会为我们在cookie中保存一个键值对,键为remember-me,值为系统生成的token。这个token是系统根据用户名和密码自动生成的,同时会设置上过期时间,只要我们在过期时间前访问页面,我们都会带上这个cookie,而系统会根据token的值判断该用户是否已经登录。

这是有一个问题,我们每次请求时,系统都会给我们带回这个cookie信息,我们请求别的页面时,会自动带回给系统。但是如果有人恶意抓取了这个cookie信息,获得了token那么他就可以伪造用户用户去登录了,这样就有隐患。而且还有一种隐患token是根据用户名和密码加密生成的,万一加密的渠道被破解了,那就等于变相把用户名和密码告诉别人了,所以我们需要采取另外一种方式来实现remember-me功能。

正文

这时我们采用持久化token的方式来存储token

在客户端的cookie中,仅保存一个无意义的加密串(与用户名、密码等敏感数据无关),然后在数据库中保存该加密串-用户信息的对应关系,自动登录时,用cookie中的加密串,到db中验证,如果通过,自动登录才算通过。

具体怎么做呢?

首先需要在对应数据库中创建一个表,这个表的表名和字段都是写死的,不要改动。估计可能是底层sql语句就是固定写好的。

CREATE TABLE persistent_logins (
  username varchar(64) not null,
  series varchar(64) not null,
  token varchar(64) not null,
  last_used timestamp not null,
  PRIMARY KEY (series)
);

创建好表之后,在配置类中注入一个数据库连接池类:

    @Autowired
    private DataSource dataSource;

这里因为要持久化token,引入一个类jdbcTokenRepository,这个类实现了一个接口persistentTokenRepository,我们点进去这个接口:

public interface PersistentTokenRepository {
    void createNewToken(PersistentRememberMeToken var1);

    void updateToken(String var1, String var2, Date var3);

    PersistentRememberMeToken getTokenForSeries(String var1);

    void removeUserTokens(String var1);
}

看方法名字,不难发现这个接口实际上是对token进行增删改查的。平时默认Security中会自动注入一个该接口的实现类InMemoryTokenRepositoryImpl,这个类存储token是在内存中的。就是上文介绍的实现remember-me的方法,这个时候我们需要往ioc容器中注入另外一个接口实现类JdbcTokenRepositoryImpl,这个作用就是将token存储在数据库中。

在配置类中注入组件:

	//注入持久化token的组件
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;

最后一步,指定使用的token存储器(我这么叫的.):

	http.rememberMe().tokenRepository(persistentTokenRepository()).tokenValiditySeconds(1209600);

第二个方法tokenRepository(persistentTokenRepository())就是指定token存储器,tokenValiditySeconds(1209600)是设定过期时间。

我们登录测试一下
在这里插入图片描述
去数据库刚刚创建好的表中,可以看到里面已经有数据了。

在这里插入图片描述
至此,我们的token就存储在数据库中,这样安全性也得到了提高。

猜你喜欢

转载自blog.csdn.net/Jokeronee/article/details/106646876