背景
后台管理系统,使用技术如下:
后端:springcloud,springsecurity
前端:AntDesign Pro v4,React
前端有多个项目,本地开发时,多个前端项目在不同的端口上启动,部署到环境后通过同一个一级域名下的两个不同的二级域名去访问两个前端系统,要求是系统间session能够共享。
问题描述
本地开发时,通过localhost:8000和localhost:8001访问两个前端系统,可以做到session共享。假设localhost:8000访问的前端为系统A,localhost:8001访问的前端为系统B,登录A后可以经由A跳转到B而不用登录,反之亦然,系统A退出登录后系统B同样也退出登录。
但是部署至环境后,配置了a.xx.com访问系统A,b.xx.com访问系统B,但是系统A登录以后经由系统A跳转到系统B发现没有权限,并跳转到登录页。
在验证失败的AuthenticationEntryPoint类中打印出AuthenticationException如下图所示。
以上为问题的描述:即同样的一级域名下不同的二级域名之间session无法共享。
解决办法
第一步,尝试本地复现问题,发现本地用localhost:8000和localhost:8001访问时,二者均能够互相跳转,不存在session没有共享的问题,本地复现比较困难。
第二步,google或百度“前车之鉴”,用springsecurity session;spring跨域 session;设置cookie等等不同的关键字搜索,查到解决方式之一,用如下的配置来指定cookie的domain,尝试后无效;
第三步,尝试观察验证失败的错误信息,从抛出的异常:InsufficientAuthenticationException到抛出异常的代码ExceptionTranslationFilter、SessionManagementFilter,尝试从spring-security-web的源码中去倒退问题,后发现这串逻辑是在遍历filter中执行的,且由于本地无法复现,很难找到精确的问题所在,遂放弃。
第四步,由于通过前三步的尝试,基本可以确定是Spring Security或Spring Session的问题,因此决定直接上Spring的官网寻找答案。
https://spring.io/projects/spring-security
如下图所示,Spring Security中的三项快速的过了一遍发现没有什么有价值的信息;
由于我们系统用的是redis存储session,所以直接再看Spring Session中的Spring Session Data Redis这一栏,直接点到LEARN,找到最新的Reference Doc.查看文档。(这里需要注意一下版本,我用的是比较新的版本,因此这边直接选择了Current的文档。)
通过上面的排查步骤我可以猜测问题与domain相关,于是尝试用domain关键字查询全文,最终在9.13.1处看到这样一句话:
This allows sharing a session across domains and applications.
到这里基本上可以断言这部分内容可以解决我的问题了,所以根据文档中的内容,自定义一个CookieSerializer,并将domain设置成我们需要的一级域名比如:
xx.com
即可。部署至环境后系统间成功跳转,问题解决!
另,这里spring的官方文档上对domainName这个参数也解释到,这个参数虽然容易理解,但是在实际开发中,通常就需要再开发环境和生产环境上使用不同的配置,会比较麻烦,不够灵活,因此文档建议使用domainNamePattern这种正则表达式的形式来配置。
后
官方文档yyds!