原创

Spring Security(2)——实现Remember Me功能(附完整项目代码)

1. 简述“记住我“功能的用处

生活中我们常用的淘宝,京东,博客等一众网站,都会有自动登入的选择框,其实这就是“记住我“功能,在security框架中,就以及设计并实现了相关的逻辑,供开发者进行配置化开发。

Remember Me功能,用户重新打开浏览器访问网站的时候,不需要重新进入登入页面来登入,可直接访问网站的页面及使用相关的功能。

读者朋友们可以试试我提供的Demo样例,该样例是基于SpringBoot的Security项目,可直接运行。访问路径http://localhost:8080/admin。登入用户名密码有:root/666666, guest/111111。

运行项目后,按照如下步骤来测试 Remember Me功能的效果。

访问路径后,首先登入 不选记住我,登入成功后,关闭该网页标签但不关闭整个浏览器,再次访问http://localhost:8080/admin发现不用再登入。这个并不是记住我功能,而是浏览器没有关闭,cookie保存在浏览器内存,当再次访问的时候就能再次使用。

但是如果关闭了浏览器进程,cookie就会消失,因此再次开启浏览器并访问这个地址,就需要重新登入了。

如果登入时候选中Remember Me,那么cookie就会保存在浏览器,每次用户访问路径的时候就会从cookie中取出登入token数据,如果token没过期,就能直接访问网站的页面了。两种认证方式如下图所示:

alt

不过,这里我们是吧cookie数据存放在内存的,有个弊端就是服务重启后数据就会消失。浏览器就需要重新登入。

2. 记住我功能的实现

登入页面添加remember-me选项

在demo项目的login.html页面中添加记住我选项。

<div class="form-group">
    <input type="text" name="username" id="username" class="form-control input-lg"
           placeholder="UserName" required="true" autofocus="true"/>
</div>
<div class="form-group">
    <input type="password" name="password" id="password" class="form-control input-lg"
           placeholder="Password" required="true"/>
</div>
<div class="form-group">
    <input style="width:46px;height:26px" type="checkbox"  name="remember-me"  id="remember-me"/><font  size="5">记住我</font>
</div>

在SecurityConfiguration配置类中添加remember me。

......
.and()
.rememberMe()
......

在configure(HttpSecurity http)方法中添加上代码,即可开启rememberMe功能。浏览器关闭后访问网站不需要重新登入。

3. 记住我功能分析

如果要分析“记住我“功能,就必须来看看security的整个架构。如下图所示;

alt

在绿色部分是security框架的认证过滤器,只要一个认证过滤器认证通过,则用户就登入成功,我们第一次登入的时候使用的是UsernamePasswordAuthenticationFilter进行认证,选择了“记住我“后,再次访问网站的资源时候,就会使用RemeberMeAuthticationFilter认证过滤器。

开启remember-me后,会在security框架中的某个流程阶段判断是否保存token值,这个代码片段如下:

parameter = "remember-me";
......
if(!rememberMeRequested(request,parameter)){
    return ;
}
onLoginSuccess(...);
......

private PersistentTokenRepository tokenRepository = new InMemoryTokenRepositoryImpl();

......
// 保存Token
tokenRepository.createNewToken(persistentToken);
// 将Token写到Cookie中
addCookie(persistentToken, request, response);

......

所以登入form中的checkbox组件名称为remember-me。在这里需要判断是否存在这个参数,存在则继续 生成token并保存。默认保存在内存中。

4. 基于内存实现会有什么问题

服务重启导致重新登入:基于内存来保存用户的登入token,遇到服务重启的情况,用户就需要重新登入。

集群部署服务导致多次登入:集群模式下部署登入服务,用户请求被nginx分发到不同的服务器,每次到新的服务器都要再重新登入一次。

这些都是基于内存来实现remember-me功能带来的问题,而针对这些问题我提供了两种有效的方法来解决,感兴趣的读者请查看我的下面两篇文章(撰写中,敬请期待.....)。

完整的demo项目,请关注公众号“前沿科技bot“并发送"SEC-THREE"获取。

alt

正文到此结束
本文目录