多项目共享session实战

这周工作中遇到的一个问题就是要把组内的两个项目(完全不同的两个项目,没有任何关联那种)做成统一入口。这里用A,B来代指两个项目。
现在要做成去掉B的登录,然后在A的项目里用iframe的形式把B的页面嵌入到A项目中。首先这两个项目的权限是单独在另一个平台获取的。所以理论上这种实现是完全可行的。但是具体的实现其实一步一个坑。当然了有一些也是我个人问题。下面从头开始讲思路。

第一步思路:Session从内存中移出

首先简单介绍下我这里为什么会说到Session共享。因为之前两个项目都是基于session实现的鉴权。所以出于最小改动原则,我这里还是要继续使用session而非JWT。
然后说到两个项目的鉴权都是用session实现的,但是基于内存的session肯定是无法实现共享。所以这里第一步是换成redis-session。

redis-session的使用

两个项目都是spring项目,所以大大简化了引入redis-session的过程。主要分散步:

1. 导入依赖

        <!-- 引入 spring-session 依赖 -->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
        <!-- 引入 redis 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

需要注意的是如果我们只是使用redis存储session,是不需要引入下面的redis依赖的。我这里之所以引入这个依赖是为了对redis进行一些查询操作。

2. 添加redis配置

关于redis的配置,最基本的连接配置,还有一个很重要的注解,就是session的存储方式是redis。如下:

 spring:
  session:
    store-type: redis #session 存储类型
  redis:
    database: 2
    host: 127.0.0.1
    port: 6379

因为我这里是测试环境,所以也没设置密码。如果你的redis还想有一些别的配置按需自己配吧。

3. 启动类添加注解

@EnableRedisHttpSession  //开启使用redis存储session

只需要这三步,我们就会发现session存入redis中了。我们可以用测试代码试一下,请求中随便set到session中点东西。

    @GetMapping("/test")
    public Object test(HttpServletRequest request){
        request.getSession().setAttribute("test",12);
        return null;
    }

然后我们打开redis可视化软件看一下是不是增加了一个session:


session存到redis中

到了这里,session存到redis中已经实现,两个项目都改好之后,该考虑如何共享了。

第二步思路:共享redis中的session

试错一:假装是一个session

到了这里网上开始有参差不齐的声音了。一种是说什么判断是不是一个session是根据cookie中传的session值,然后我就信了。当时第一反应,让两个项目的cookie中的session值是一样的不就行了么

请求中的session

然后我本来是打算获取A项目中请求的session,然后传给B项目的一个接口。让前端把这个值设置成session的值。
一顿操作后发现不可行。最后想到一个很好的测试方法:A登录完成后获取到session,我直接在postman中调用B服务的接口,将session的值写入。请求后发现request.getSession(false)是空。所以根据说明这个判断方式完全行不通。
反正我也不知道是我操作问题还是这个说法本来就是假的,如果有实测成功了的朋友欢迎来辩

试错二:nginx转发

这是我们组的一个大佬提出来的思路。就是前端请求都用A服务的域名包装一下,这样session肯定是一致的。
首先在B项目的前端配置:请求路径改成a.com/bbb/xxx
这里的a.com是A项目的请求地址,/bbb是自定义的一个基础前缀。为了区分实际上的b项目的请求。 /xxx是原本b项目接口的请求路径。
比如原本b的一个接口: b.com/user/info
现在改成: a.com/bbb/user/info

然后在A项目的nginx中配置一个转发:


nginx请求转发

因为我们项目的私密性,所以这里贴出来的是百度的转发方法。其实就是设置/bbb 的请求转发到b项目原本的后端地址上。
理论上请求是同一个地址出来的,session应该是一个了吧。然后运行项目一跑,发现转过去的还是没有session。
后来百度是因为域名不同,自动清了cookie。因为nginx这块的配置一直都是我一个同事来的。所以到此这个想法就失败了。
当然我之前百度说有一种方式可以跨域名,事实证明这种配置没啥用。不确定是不是因为我们这边前端有什么特殊处理(因为浏览器查看的session和存到redis中的sessionId不一致)

location ~ /xxx/ {
proxy_cookie_domain b.com a.com;
proxy_pass http://b.com;
}

勉强实现三: 以A模块为核心代码维护B模块的session

这里其实不算是试错了,但是实现的方式我自己挺不满意的。当然了时间紧任务重,目前这个功能是这么实现的。
因为需求的前提是A,B两个项目会存在session过期时间不一致。而且B是挂在A项目里的,这就有个问题,B项目session失效的话,其实是没办法跳到登录页的。所以要保持session过期时间一致。所以如果不能共享的话,手动维护两个session有效性一致也可以。
这也就是我上面引入依赖的时候要引入data-redis的原因啦。
这个代码维护就简单的很。获取A项目的sessionId。然后放在B项目请求的header中.然后在b项目中做判断:

  • A有session,B也有session,放行
  • A没有session,B也没有session,放行
  • A没有session,B有sesion, B的session删除
  • A有session,B没有session,A的session删除

以上四个逻辑可以保证A,B的session要么同时生效,要么同时不生效。代码逻辑其实也很简单,我就截图的形式展现下。


image.png

另外使用redis的时候还有有个小插曲,最开始我用的是RedisTemplate。当时也就图个简单,结果发现获取不到key。最后发现这种带有:的层级结构的key,不能直接取出。哪怕用redisTemplata.key("*")也获取不到。当然了也存不了。
估计是有什么用法, 但是因为我以前项目中我知道层级结构的是可以取的,所以找了半天原因最后换成StringRedisTemplate就可以了。
还有一个就是默认的redis-session存session的时候序列化有点问题,取出来的不是存进去的字符串,这是因为默认会采用jdk的序列化方式。这个单独设置下序列化方式就行了。

到这里其实让A,B伪共享session就算实现了。之所以说伪共享是因为只做到了一个没有另一个自动删除。更合理的应该是一个存在另一个自动创建。这个其实也容易实现。就是发现其中一个存在自动调用另一个的登录接口创建session,我这里图简单也没写。我上面说觉得这种方式不太满意是每次都校验其实挺没必要的。但是目前也没找到更合适的方式。
本篇笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注。如果大家有更好的实现方式欢迎提出,或者有什么建议也行,共同进步嘛!也祝大家工作顺顺利利!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容