第十一节 Remember Me

版权声明:欢迎转载大宇的博客,转载请注明出处: https://blog.csdn.net/yanluandai1985/article/details/86303610

一、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数据。点击此超链接,因为当前用户没有登录,所以请求会被重定向到登录页面。在shiro.xml中可以查看相关配置。

         请求被重定向成为 /actions/login,这个请求我在Controller中的处理方法是,跳转登录的login.jsp页面。我在login.jsp页面中,使出浑身解数,引入了bootstrap,把输入框与按钮做的稍微精致一丢丢,以掩饰我前端helloworld级别的事实(偷笑)。

 

        我们在提交之前,我们现在后台的UserController类中的authentication方法中的第一行打一个断点。

        登录页面中,用户名与密码输入 jay / 123456 即可,并且勾选"记住我",点击提交表单,请求到达后台断点处。

        接下来,我们就要详细分析使用RememberMe功能的核心代码了。

        首先,来看下图的authentication方法的具体实现。首先获取到Subject门面对象,然后把我们输入的jay与123456封装成一个UsernamePasswordToken对象,将这个token交付给shiro做内部认证。此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拦截器就是"记住我"拦截器。当用户没有退出,但是关闭了浏览器之后,重新打开另外一个页面访问服务器,并再次访问受限制页面。这个时候是可以直接访问到受限制页面的,不需要再次登录。联想到一些购物网站,如果登陆后关闭浏览器,再次访问购物网站,通常情况下那个网站不会在要求你进行登录。

猜你喜欢

转载自blog.csdn.net/yanluandai1985/article/details/86303610