《应用拆分与平台搭建最佳实践》- 单点登陆
单点登陆,字面就可以看出,只有一个登陆点,详细来说,所有的系统都只有这一个登陆点。所有的系统都依靠这个点来进行登陆,其实就是一个共享的登陆平台。
首先我们来学习下登陆的原理: session与cookie
一个session 对应的就是浏览器到服务器的一个会话线程,但是后段服务器往往是被nginx代理的集群。因此如何在多机器中共享会话,就成为了个问题。这个时候,我们需要一个token,在多个系统中传递,可查询。常规做法是将token在后段存入 redis,这样,任何一个系统需要的时候,都去redis集群中获取。那前端存在哪里呢,针对于这种情况,有很多奇葩的做法,比如让所有的请求连接后面都带这一串token,对于研发而言,简直是灾难性的,重复劳动。了解过http报文协议的都能知道,http报文是可以夹带数据的,那用那种夹带方式更好呢。这个时候cookie的功能就体现了出来,存储在浏览器端的数据,每次请求会被带到服务端。
说到cookie不得不提到 cookie的域,cookie针对于任何一个域名(例如xiaotian.shi)都认为在一个域内,我们将域在服务器端配置成为(xiaotian.shi)三级域名可以随便写,三级域名就可以成为子系统的域名。
举个例子:
login.xiaotian.shi
www.xiaotian.shi
portal.xiaotian,shi
这样写的话,cookie带回来的都是同一个值,不会被重制。
当然也有更改服务器为跨域服务器的方式,但是这种实现较为复杂,很考验架构师的能力。笔者参考了很多互联网公司的实现方案,都是基于多三级域名的方式。
很多人就想了,那为什么不用nginx直接配置成子路径的方式呢?
www.xiaotian.shi/login
这种方式也是可以实现cookie跨域,从而实现会话跨应用共享。但是对于研发应用而言不友好,业务线上的研发人员水平参差不齐,不能有这种过于繁琐的请求地址要求。一旦写错,发到线上就会引起事故。所以我们应该屏蔽这种问题,一个域名一种系统,大家相互隔离开。
我们来看看实现效果,注意看地址栏,域名的变化
1.登陆系统(login)
2.www系统
3.管理站(portal)
4.监控站(monitor)
当同一个浏览器访问任何一个站点时,如果没有登陆,都会跳转回登陆界面,登陆一次,3个系统都可以访问对应权限的资源。
注意:这三个地址,对应的是3个不同的应用系统,而不是传统的一个应用,发3个机器。
这么说可能有些抽象,上个图
同应用会话共享
访问xiaotian.shi 可能会又负载均衡分配到的任何一台机器访问到。
跨应用会话共享
我们希望
(三种颜色对应不同的应用系统)
但是,负载均衡依然还是根据系统来的
总而言之,访问前面的资源都是各自应用的资源,但是会话资源是共享的。
对于用户而言,如果不看top,感觉不出来应用系统发生过切换。
那如何在技术层面,实现!
技术架构:
以笔者的基于spring boot的实现为例子。(笔者会在github上提供完整的代码demo,地址稍后会补充)
首先,我们需要对session-cookie进行特殊配置
spring boot 原生基于纯配置文件配置的方式不可取,笔者已经多次尝试,并阅读了源码。
首先,还是传统的spring 配置文件,配置redis session bean
几种系统都需要配置同一套,,所以最好写个sample,方便其他应用需要接入的时候使用。
配置参数:
# Redis数据库索引(默认为0) #spring.redis.database=0 # Redis服务器地址 spring.redis.host=192.168.1.xxx # Redis服务器连接端口 spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password= # 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-active=8 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-wait=-1 # 连接池中的最大空闲连接 spring.redis.pool.max-idle=8 # 连接池中的最小空闲连接 spring.redis.pool.min-idle=0 # 连接超时时间(毫秒) spring.redis.timeout=0 # domain server.session.cookie.domain=xiaotiandev.shi server.session.cookie.http-only=true server.session.cookie.name=MSESSION server.session.cookie.path=/
重点在
# domain server.session.cookie.domain=xiaotiandev.shi server.session.cookie.http-only=true server.session.cookie.name=MSESSION server.session.cookie.path=/
重中之种在于
server.session.cookie.domain=xiaotiandev.shi
配置域只配置到二级,不配置3级。
这就是前面网站截图中cookie出现的内容
MSESSION 相当于sessionid
具体值会存入redis中
可以通过redis-cli工具进行确认。
完成这一步,会话的共享基本完成,但是距离完成单点登陆的功能还有段距离。
我们需要配置域名的解析
一般测试和生产环境都是使用nginx做负载均衡,很多大牛都写过nginx的负载方案,和完整的报文转发策略,这里就不献丑了。大家有需要了解nginx如何配置,可以自行百度。
本机我直接设定hosts文件
终端下:
sudo vi /etc/hosts
127.0.0.1 login.xiaotiandev.shi
127.0.0.1 www.xiaotiandev.shi
127.0.0.1 portal.xiaotiandev.shi
127.0.0.1 monitor.xiaotiandev.shi
127.0.0.1 eureka.xiaotiandev.shi
多个机器开多个实例(tomcat多实例的方案,也会在后续给出,之后会填写在此处)
4个应用端口号,分别为8081,8082,8083,8084
应用启动完成后,如果你的请求完全是页面渲染的,没有问题。到这一步,会话已经完成共享。
但是如果你有跨应用3级域名的json调用需求,那么需要注意,浏览器还是会爆出来跨域拒绝。
这里有2种解决方案:
第一,为每个服务器配置跨域允许的拦截器,为服务器增加负担,还有安全隐患。
第二,基于jsonp的调用方案(方便快捷,应用拆离的时候,有很多相互调用,都可以解决)。
最后:
我们如何解决多应用,风格统一呢?
我们如何让应用能共享top头,共享导航这些资源呢?
我们应用开发如何才能更快的接入单点登陆,不需要关心top,nav这些东西,只关注自己应用业务的开发呢?
这三个问题,会在跨应用静态资源中详细解说,请点击这里进行下一节阅读。
项目地址 https://github.com/shixiaotian/xiaotian.shi-plat.git
demo http://www.miledao.top/
账户密码
admin admin
user1 user1
user2 user2
user3 user3
账户密码
admin admin
user1 user1
user2 user2
user3 user3