问题分析
两个应用部署在同一个服务器上,默认情况下会共享同一个 Tomcat 容器,因此它们的 session 也会共用同一个存储空间。当系统 B 登录后,系统 B 的登录用户信息被写入 session;此时访问系统 A 时,由于两个应用共享 session,系统 A 的拦截器自然能读到系统 B 写入的用户信息,从而误判为已登录。
java
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User u = (User) request.getSession().getAttribute("user");
if (u != null) {
return true;
}
return false;
}
解决方案
要解决两个应用 session 互相访问的问题,核心思路是让两个应用使用各自独立的 session,互不干扰。常见做法有以下几种:
方案一:修改应用上下文路径
这是最简单直接的方式。将两个应用部署在不同的上下文路径下,Tomcat 会为不同上下文分配独立的 session 空间,两个应用之间互不干扰。
具体步骤如下:
- 打开 Tomcat 的
conf/server.xml配置文件。 - 在
<Host>节点下找到<Context>配置,为系统 A 和系统 B 分别配置不同的path属性,例如:
xml
<Context path="/systemA" docBase="/opt/apps/systemA" reloadable="true" />
<Context path="/systemB" docBase="/opt/apps/systemB" reloadable="true" />
- 保存配置后重启 Tomcat 服务。
- 此时系统 A 的访问地址为
http://服务器IP:端口/systemA,系统 B 的访问地址为http://服务器IP:端口/systemB,两个应用各自拥有独立的 session,互不影响。
方案二:配置独立的 session cookie
如果两个应用必须部署在同一个上下文路径下,可以通过为两个应用设置不同的 session cookie 名称来避免 session 串用。
具体步骤如下:
- 在系统 A 的
web.xml中配置独立的 session cookie 名称:
xml
<session-config>
<cookie-config>
<name>JSESSIONID_A</name>
</cookie-config>
</session-config>
- 在系统 B 的
web.xml中配置另一个独立的 session cookie 名称:
xml
<session-config>
<cookie-config>
<name>JSESSIONID_B</name>
</cookie-config>
</session-config>
- 如果使用 Spring Boot 内嵌 Tomcat,可以在
application.yml中配置:
yaml
server:
servlet:
session:
cookie:
name: JSESSIONID_A # 系统 A 使用
- 重启两个应用后,浏览器会为系统 A 和系统 B 分别保存不同的 session cookie,系统 A 的拦截器只能读取到系统 A 自己的 session,不会再误读到系统 B 的登录信息。
方案三:使用独立的 session 存储
如果两个应用必须共享容器,且需要更灵活的 session 管理,可以为两个应用分别配置独立的 session 存储介质,例如不同的 Redis 库。
具体步骤如下:
- 在系统 A 的 Spring Boot 配置中,指定使用 Redis 的 0 号库存储 session:
yaml
spring:
redis:
host: 127.0.0.1
port: 6379
database: 0
session:
store-type: redis
- 在系统 B 的 Spring Boot 配置中,指定使用 Redis 的 1 号库存储 session:
yaml
spring:
redis:
host: 127.0.0.1
port: 6379
database: 1
session:
store-type: redis
- 重启两个应用后,系统 A 的 session 写入 Redis 0 号库,系统 B 的 session 写入 Redis 1 号库,两个应用的 session 数据完全隔离。
- 系统 A 的拦截器在读取 session 时,只会从 0 号库读取,因此无法获取到系统 B 的登录信息。