一、Remember Me能解决什么问题
(1)当用户没有退出且关闭了浏览器,再次打开网站则不需要再次登录。
(2)当用户在登陆时勾选"记住我",退出登录后,下次登录的时候,登录表单会记住上次的登录名。
我已经搭建好的Shiro集成SSM框架,并且已经集成了RememberMe功能,如果你愿意下载我的源码的话,我很乐意与你一起探讨Shiro的RememberMe功能。希望你能够跟着我的思路一起走下去。
下载好之后,你需要修改你的数据库配置,以及导入我的t_user.sql 文件。我本机使用的数据库环境如下。
二、如何在Shiro中配置Remember Me
首先,你需要在shiro.xml中配置Cookie模版,因为用户名会被保存到cookie中且保存在用户本地。
<!-- 会话Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="sid"/>
<property name="httpOnly" value="true"/>
<!--maxAge=-1表示浏览器关闭时失效此Cookie -->
<property name="maxAge" value="-1"/>
</bean>
<!-- rememberMeCookie:即记住我的Cookie,保存时长30天 -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="2592000"/><!-- 30天 -->
</bean>
<!-- rememberMe管理器 -->
<bean id="rememberMeManager"
class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).
decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
<property name="cookie" ref="rememberMeCookie"/>
</bean>
然后在securityManager对象中引入此rememberMe管理器。
<!-- securityManager 对象-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 引入UserRealm -->
<property name="realm" ref="userRealm"/>
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
好了,经过上述两部配置,我们的Shiro已经能够使用RememberMe功能了,是不是很简单。
三、分析记住用户名功能
启动项目后,我们来到了项目的首页index.jsp页面。不好,大宇的前端水平暴露了。
页面中,第一个"测试超链接"的URL是 /actions/obtainAllUses,希望获取到当前项目的数据库中的所有User的JSON数据。点击此超链接,因为当前用户没有登录,所以请求会被重定向为/actions/login。在shiro.xml中可以查看相关配置。
请求被重定向成为 /actions/login,这个请求我在Controller中的处理方法是,跳转登录的login.jsp页面。我在login.jsp页面中,使出浑身解数,引入了bootstrap,把输入框与按钮做的稍微精致一丢丢,以掩饰我前端helloworld级别的事实(偷笑)。
我们在提交之前,我们现在后台的UserController类中的authentication方法中的第一行打一个断点。
登录页面中,用户名与密码输入 jay / 123456 即可,并且勾选"记住我",点击提交表单,请求到达后台断点处。
接下来,我们就要详细分析使用RememberMe功能的核心代码了。
首先,来看下图的authentication方法的具体实现。首先获取到Subject门面对象,然后把我们输入的jay与123456封装成一个UsernamePasswordToken对象,将这个token交付给shiro做内部认证。subject.login(usernamePasswordToken);这句代码会将此token将会最终被传入到自定义Realm中进行校验。我们自定义的Realm将会查询数据库,根据jay去到数据库中找它的密码,如果找到的密码与用户输入的123456一致,那么本次登录成功。
在subject.login(token)方法之前,先为这个token设置了是否启用RememberMe。因为我们页面上打了勾,所以是启用RememberMe功能的。
在subject.login(token)步骤后,接下来就是进行RememberMe功能的相关方法了。为了能够达到用户关闭浏览器后,再次访问网站仍然能够记住用户的身份,shiro会把用户身份信息存放到Cookie中,保存在用户的本地。下次用户在访问网站的时候,会带上这个cookie,shiro会解析出这个cookie,从而不会要求用户再次登录。
首先创建一个Cookie对象,并将其命名为"projectKey",然后配置cookie保存的时间为一年,且支持HTTP方式。接着设置cookie的保存路径是"/","/"的含义就是部署环境的根目录。如果这个项目是分布式部署,那么将cookie部署在根目录的好处就是,所有服务器都能够访问这个共享cookie。
rememberCookie.setValue(userName);这句代码就是把我们输入的用户名保存到cookie当中。下次登录的时候,就不用输入用户名了,因为用户名会从cookie中获取,这个就相当于记住帐号功能。
最后,rememberCookie.saveTo(request,response),委托request与response对象把本次的cookie保存到本地。
方法执行完毕后,返回的是 ModelAndView("home");所以,登录成功后,来到了home.jsp页面。
在home.jsp页面上,点击最下面的超链接,发送/actions/logout请求,进行退出操作。因为已经在shiro.xml中配置了退出请求使用shiro的退出拦截器logout拦截器,用户已经退出。退出拦截器在退出后,会自动重定向到项目的根目录。
退出后再次来到项目的根目录。
在点击第一个超链接"测试超链接"之前,我们在userController的login方法上打一个断点。然后再点击第一个超链接。因为我们已经退出,所以根据shiro的配置,第一个超链接的 /actions/obtainAllUses请求会被重定向为 /actions/login请求。所以,就来到了我们的断点处。
我们再来看看断点处有什么。首先是创建一个叫 "projectKey"的Cookie,然后再设置它的共享路径。
接下来就是最关键的一句代码了。这个cookie委托request对象去"/"这个路径下找同名的Cookie对象。如果有的话,把这个Cookie对象保存的值读取出来。显然之前我们在登录的时候就创建过叫"projectKey"的Cookie,并且也保存过这个Cookie的值是用户输入的登录名"jay"。所以,希望被记住的用户名usernameFromCookie就被被顺利的查到了。
final String usernameFromCookie = rememberCookie.readValue(request, null);
查到了Cookie中存储的username,然后我们把它放到session中。并返回login.jsp页面。用户名输入框会回显查到的username。所以,页面的输入框就能显示我们的用户名啦!
接着,我们输入密码"123456",但是不要勾选"记住我"哦。在后台处理表单登录的UserController的
@RequestMapping(value = "security/login", method = {RequestMethod.POST})
public ModelAndView authentication(...)
方法内再次打个断点。你可以与我在图里面打的断点处保持一致。点击提交按钮,来到断点处。
因为这次没有勾选"记住我",所以代码来到的else语句里面。在else语句里面,将此cookie移除。因此,下次在登录的时候,用户名就不会回显了。如果登录成功,你会跟我显示的一样。
四、分析记住我
重启项目。
点击第一个超链接后进行正常登录,需要勾选"记住我"功能。
关闭掉当前服务器页面。重新开一个新的页面。再次访问服务器根目录:http://localhost:8080/
点击第一个超链接"测试超链接",发送/actions/obtainAllUses请求,请求成功,页面上返回所有用户的JSON数据。说明即使退出了浏览器,但是我如果没有退出,那么下次再次访问服务器的受限制页面,也是可以的,不用再次登录。
我们来看一下后台的Shiro配置。第一个超链接发送/actions/obtainAllUses这个请求,使用了user拦截器。user拦截器就是"记住我"拦截器。当用户没有退出,但是关闭了浏览器之后,重新打开另外一个页面访问服务器,并再次访问受限制页面。这个时候是可以直接访问到受限制页面的,不需要再次登录。联想到一些购物网站,如果登陆后关闭浏览器,再次访问购物网站,通常情况下那个网站不会在要求你进行登录。
好了,本期的RememberMe功能的探讨就到这里了,大宇十分感谢你能够看到这里,我们下期再见o(∩_∩)o 。
五、源码下载
本章节项目源码:点击我下载源码
----------------------------------------------------分割线-------------------------------------------------------
下一篇:第十二节 Shiro会话管理
阅读更多:跟着大宇学Shiro目录贴