0%

解决session共享,实现单点登录

2018年3月9日 下午2:53

  1. 在pom.xml中引入jedis2.6.0版本
    1. 与redis连接的javaAPI
  2. 创建_common_RedisPool 类
    1. 变量要使用static类型,因为要在tomcat启动的时候就配置好连接池
    2. initPool()只使用一次,并且要在tomcat启动的时候就调用,所以要放在静态块中岁tomcat启动时就初始化pool
    3. 其中主要使用了我们引入的外部api
      1. JedisPoolConfig
      2. JedisPool
    4. 对外部使用者来说,我们上面的两个对象是隐藏的,只有一下三个方法用于操作JedisPool的pool对象
      1. getJedis
      2. returnBrokenResource
      3. returnResource
  3. 在mmall.prooerties中配置RedisPool的各种属性
    1. RedisPool中使用PropertiesUtil读取配置
    2. 都是连接池的配置或者是连接Redis的账户信息
  4. 书写main函数进行测试,看是否能将数据写入到redis中
  5. 创建_util_RedisPoolUtil工具类
    1. 利用RedisPool中放出来的三个方法,将需要的redis的命令进行封装,主要都包括
      1. 获取jedis实例
      2. 执行语句
      3. 放回连接池
  6. 书写main函数进行测试,通过打断点,单步进行观察

序列化,反序列化原因

  1. 我们现在需要将我们的用户session存储在redis中 ,但是redis中不能不能直接存储User对象,我们只能使用序列化的方法:将User对象序列化为json,然后用redis中的string类型进行存储

  2. 创建_util_JsonUtil类

    1. 配置序列化的各种属性
    2. 配置反序列化的各种属性
    3. 重点:
      1. 使用typeReference,解决List这类问题
      2. 在Intellij IDEA中使用Debug - bojiangzhou - 博客园
        1. 计算表达式功能
        2. 变量查看功能
      3. 参数中,使用Class<?>代替Class原因
        1. 我们在参数中要使用的class类型不确定,此时可以使用任意一个
        2. 但是,当我们参数中的类型与函数的返回值类型不是恒定不变的一对一的关系时,我们就只能使用Class<?>
      4. 我没有看6.9节的源码解析
  3. 在controller中将session的保存用redis缓存来代替

    1. session.getId()作为redis的key值
  4. 配置tomcat启动配置,设置两个tomcat,tomcat1、tomcat2

    1. 注意tomcat2的端口配置
    2. 即使这里设置了两个,但是真正运行的时候idea只能在一个tomcat上部署
  5. 复制整个项目,改个名字就行,然后用idea打开这个复制好的项目,选择new windows。然后,在这个项目中运行配置选择tomcat2,运行。

  6. 打开已经配置好对域名www.imooc.com负载均衡的nginx服务器

  7. 配置host,让域名www.imooc.com指向nginx的127.0.0.1

    1. 测试,ping www.imooc.com看是否指向127.0.0.1
    2. Reload nginx,因为nginx在负载均衡转发的时候,我们在分流的配置项中写的是www.imooc.com,而不是127.0.0.1。nginx在解析这里的www.imooc.com时,还是需要我们本机的host文件。所以,**配置host之后,一定要reload nginx**
  8. 在浏览器中访问www.imooc.com,看到tomcat1,Tomcat2随机访问

现在的问题是:当我们分别访问tomcat1、tomcat2时,双方的登录信息sessionid不能共享。也就是说,当tomcat1登录之后,tomcat2依然没有登录

  1. 创建_util_CookieUtil
    1. 利用Cookie对象来操作管理浏览器的sessionid
    2. 通过domain按域名划分cookie的共用范围
    3. 设置存在时间(或者销毁)
    4. 这个过程是如何与浏览器进行信息的传递呢?
      1. 就是我们servlet最原始的request+response完成与浏览器的交互过程
    5. cookie和session这篇文章很关键
  2. 当用户登录信息正确时,我们将使用CookieUtil的writeLoginToken向发出请求的浏览器发送一个名字为mmall_login_taken的cookie,值为sessionId。
    1. 如果不正确的话,服务器只会给浏览器一个Jsessonid,对于Jsessonid,是请求都会给,这就导致了每次的访问都会更改JsessionId的值
    2. JsessionId不等于session.getId()的值,JsessionId是一定存在的cookie,只要是个网站他就会返回给浏览器
  3. 重新发布两个相同的项目到两个tomcat中,打不开首页的处理方法
    1. 分别执行:mvn clean package -Dmaven.test.skip=true
    2. 别一块启动tomcat,分开启动
  4. 注意这时要用debug模式运行,而不是run,因为我们要打断点进行联调
    1. 在debug模式,我们的断点在更改之后,立即在下一次访问生效,不用重新启动tomcat
    2. 在debug模式,即使断点已经到来,我们依然可以在当前断点的后面增加断点,同样也是立即生效
  5. 现在就可以实现不同服务器共享session,其实准确点是共享cookie,这里的共享是按域名来划分,而不是按tomcat来划分,这是最根本的原理
    1. 可以在chrome_检查_Application/Cookies中查看登录之后,我们配置的cookie是否有了
  6. 现在只是修改了login.do,其他访问路径依然还是使用session.getAttribute。我们要session写法改成CookieUtil的写法
    1. login.do
      1. login.do的时候要使用RedisPoolUtil来写入redis当前用户的信息
    2. 其他的各种方法都是调用CookieUtil的readLoginToken来读取用户的信息
      1. 即要检查cookie有没有mmall.login.token,还要检查redis中是否真的有,双重验证。
    3. logout.do是使用delLoginToken方法
      1. 同时要使用RedisPoolUtil删除redis中对应的键值
  7. 创建_controller_common/SessionExpireFilter过滤器,用于在每次更新redis当前用的有效期
    1. 现在有两个有效期,一个是cookie的,一个是redis的,这两个缺一不可。
    2. 将过滤器这个组件加入到web.xml中
  8. 用redis来代替我们各自tomcat中的GuavaCache,因为两个tomcat的GuavaCache并不是共享的。
    1. 用户输入获取token的tomcat1,与用户最终通过输入taken来修改密码的tomcat2是不同的,这时Tomcat2就无法验证保存在tomcat1中的正确的taken
    2. 此时可以删除GuavaCache的工具类了