部署在同一台机器的不同应用,两个应用的cookie会互相影响的问题(如果做了登录拦截,会导致已登录的应用需要重新登录)

时间:2024-03-15 20:50:21

2018年5月29日记

    今天在解决项目的bug时发现的一个问题,我们有两个系统:权限管理系统(简称系统A)、前台展示系统(简称系统B),发现系统A在登录的情况下,如果在打开一个页面登录系统B,再回到系统A访问时会跳转到登录页重新登录,导致的结果系统A与系统B不能同时登录。

    初步的猜想可能是因为客户端的session或者cookie出现了问题,那会出现什么问题呢?下面我们就先认识一下session和cookie看看他们是怎么工作的吧:

   1.session(会话)

    由于http是无状态的协议,因此那么多用户在访问服务器服务器怎么知道是哪个用户在发起请求呢?,这个就是session要做的,简单的说就是用来保存当前用户的会话状态和我们想在多次请求中公用的数据,告诉服务器我是哪个用户的会话,方便在用户后续的请求时不再重新创建新的session对象;

    2.cookie

    我的理解:session是在服务器端保存用户状态信息的,而cookie则是在客户端保存用户信息的。cookie中会保存用户此次会话(session)的ID(在用户发起第一个请求后产生的session的ID),不过不加设置会保存在名为JSESSIONID的变量中(默认),以后每次请求都会将该cookie的值放到header中用于服务器去选择哪个session作为该请求的session.

说了这么多是不是还是不太理解两个东西是干什么的呀?没关系,我们来举个例子分析一下从用户打开浏览器后多次请求后台,整体的流程是什么样的,我先盗一张流程图:

部署在同一台机器的不同应用,两个应用的cookie会互相影响的问题(如果做了登录拦截,会导致已登录的应用需要重新登录)








流程是这样的:

1.当我们打开浏览器A时,此时是没有什么session的,当我们第一次访问有效的servlet时,就会创建一个httpSession对象了,该对象就是用来存放此次会话的信息的(服务器会在内存中开辟一块空间来存放session);

2.然后服务器将session对象的ID的值(如图中的11)设置到cookie对象的JSESSION字段中,在请求返回到浏览器A时浏览器将该cookie的信息进行保存(前台是可以通过Document对象获取里面信息的哦);

3.浏览器A再访问servlet2时就会在request的header中带上刚才保存cookie的值,服务器接收到请求头中的cookie信息然后就会去内存中去找是否存在ID为JSESSIONID的session对象如果存在该使用该对象作为此次请求的session,如果不存在则会创建一个新的session对象,因此服务器对此次请求会使用访问servlet1时创建的session对象,而此对象中保存了用户的信息,因此可以达到session的共享的效果。

   部署在同一台机器的不同应用,两个应用的cookie会互相影响的问题(如果做了登录拦截,会导致已登录的应用需要重新登录)

值得注意的是:

    浏览器在关闭之后代表整个session会话就结束,但是浏览器可不会通知服务器说我关闭了啊,你赶紧给我清掉啊不然出了啥问题跟我没关系哈,而且服务器自己也不会知道浏览器已经关闭了,因此session对象会一直保留在服务器的内存当中,这样必然会导致内存的泄露(多么惊悚的一个名词),这么健壮的框架肯定会有解决方案吧,对有的就是设置session的超时时间,springboot中设置是通过在application.xml中配置server.session.timeout实现的。

嗯哼,接下来重点来了啊。。。(注意力集中点部署在同一台机器的不同应用,两个应用的cookie会互相影响的问题(如果做了登录拦截,会导致已登录的应用需要重新登录)

    流程大致上明白了,那为啥会出现开头说的那个问题呢,上网各种搜啊,终于让我找到了答案,(我自己理解的啊,有大神看到了可以指正哈),就是浏览器的cookie有一个domain属性,该属性保存着这个cookie是哪个服务器使用的,这样当浏览器去请求不同服务器就可以选择合适的cookie带到后台了;

    对就是这个点,因为上面说了我们项目的应用时部署在同一台服务器上的,所以域名肯定是一样的了,那你域名一样的话,我两个应用当然都会在一个cookie里面保存JSESSIONID的数据了,导致的问题就是系统A登录过了,系统B刚登录的时候就会带上系统A产生的cookie,登录请求返回后cookie中的值就变成了系统B创建的session对象的ID了(系统A产生的cookie值被覆盖了),等系统A在发送请求的时候就会拿着系统B产生的cookie的值去系统A中找是否有该id对应的session对象,(那肯定没有啊,人家在系统B里面呢,除非你遇见鬼了部署在同一台机器的不同应用,两个应用的cookie会互相影响的问题(如果做了登录拦截,会导致已登录的应用需要重新登录)),由于找不到session对象所以服务器又给A重新创建了一个新的session对象(这可是新的对象,啥用户信息都没有)所以系统A就跑去去重新登录了。

解决方案:

    由于两个应用没有设置cookie的名称,因此session的值都会保存在默认名JSESSION中,这也是导致两个应用cookie的JSESSION互相覆盖的原因,因此给两个应用分别设置cookie的name就解决了这个问题了,设置name在springboot中通过server.session.cookie.name进行设置。

    写的有点啰嗦了,我也不是什么大神,就是感觉有必要记录一下,对自己也很有意义,有什么问题请大家留言哈