记住我基本原理
记住我这个功能应该都不陌生,就是保存用户登录信息
在SpringSecurity中实现原理是:
- 第一次,浏览器发出认证请求,由
UsernamePassword
拦截器认证后,会走到RememberMeService
类 RememberMeService
使用TokenRepository
做了两件事- 将用户信息以Token对象保存到数据库中(Mysql,Redis等等)
- 将Token放到Cookie中返回给浏览器
- 第二次浏览器请求后,会被
RememberMeAuthenticationFilter
拦截,这个拦截器会当前面一系列绿色拦截器拦截过后才会拦截 RememberMeAuthenticationFilter
请求RemenberMeService
,将请求信息传递给他RememberMeService
先读取Cookie中的Token然后使用TokenRepository
向DB查找Token
对于SpringSecurity来说,实现记住我非常简单
修改登录页面
1 | <tr> |
注意,这里name必须写remember-me
,才能被SpringSecurity获取
配置类添加存活时间
1 | public class BrowserProperties { |
向容器中注入TokenRepository
在BrowserSecurityConfig中进行注入
1 |
|
这里我们使用PersistentTokenRepository
来进行Token的控制,并使用Jdbc即关系型数据库进行Token的持久化
数据源就是application.properties
配置文件中配置的
因为对于这个实现类需要单独的表进行操作,对此可以启动时自动建表,当然第二次启动需要将其设为false或注释掉。也可以复制SQL自行建表
配置Security
1 |
|
主要代码就是以下三行:
1 | .rememberMe() // 记住我配置 |
设置TokenRepository
实现类以及存活时间
启动测试
首先看数据库
可以发现,自动创建了一张persistent_logins
表,然后进行登录
登录成功后可以发现表里多了一条数据,这时我们重启项目,清除Session,看看是否可以实现保存登录状态,
直接访问http://localhost:8080/user/me2
成功访问,并且最后使用时间修改了
记住我源码解析
第一次登录
源码解析前,我们先分析下从哪里下手,第一次登录,那么一定时全部认证过会,才会调用之前说的RememberMeService
进行Token保存,所以先去看看认证成功后处理器方法
果然有一个loginSuccess()
方法,那我们就从这里入手,Debug解析源码
1 | rememberMeServices.loginSuccess(request, response, authResult); |
首先进入到AbstractRememberMeServices
实现类的方法里,这里可以看到显示判断请求参数是否相同,我们看看这个参数默认是什么:
1 | private String parameter = DEFAULT_PARAMETER; |
就是我们知情权修改登录页面时,说的那个name值,必须固定为这个才可以,匹配上后,接着跟进onLoginSuccess(request, response, successfulAuthentication);
方法
接着进入了PersistentTokenBasedRememberMeServices
实现类,看到了两个重要方法
1 | // 创建一个新Token,保存到数据库中 |
就是我们之前放原理图时做的两件事,这样第一次登录就基本走完了。
第二次登录
第二次登录就需要查看之前说的那个拦截器了RememberMeAuthenticationFilter
,从他入手
进入到拦截器中,首先判断上下文中并没有认证用户,然后去调用RememberMeService
的autoLogin()
方法
进入此方法,通过观察,最重要的方法应该就是这个processAutoLoginCookie()
,处理自动登录Cookie,猜测应该是将Cookie中Token信息取出查库的,我们进入看看
1 | protected UserDetails processAutoLoginCookie(String[] cookieTokens, |
这里我直接将源码简化,更方便观察,代码很简单也很清晰。这样最终通过UserDetailsService
获取用户信息。
最后我们再把之前的流程图放出来,应该会有更深的理解