
SSO单点登录的需求就愈加迫切。
Redis存储
Session,这最初是为了解决应用集群部署时的
Session共享问题,却也为应用之间共享Session提供了支持,但单靠应用之间共享
Session是无法实现单点登录的。
Session中,并通过响应头的
Cookie字段将
SessionId传递给浏览器存储,后续请求服务端时,浏览器会自动在请求头加上
Cookie,所以才能保持用户的登录状态。
Redis共享
Session,集群之间可以共享
Session的原理与服务重启后依然保持登录状态的原理相同。
cookie发起请求,如果
Session未过期,那么从
Redis获取到的
Session就能继续使用。
Redis共享
Session,但要求浏览器向每个应用发起请求都能带上相同
Cookie才能实现单点登录。
Cookie共享,服务端也不能操控客户端浏览器访问不同域名下的站点都带上相同的
SessionId。要实现单点登录我们只能另辟蹊径。
Cookie,但同一个主域名的不同子域名应用间可通过配置
Cookie为主域名方式实现
Cookie共享,前提是所有子系统都共用一个主域名。这种方案可取也不可取,短期而言可取,长期而言不可取。
web应用之间相互跳转,由用户在应用
a点击按钮跳转到应用
b,也可以这样实现:当用户在应用
a点击跳转应用
b时,在跳转链接上带上
SessionId,应用
b根据
SessionId读取用户信息再写入
Session。
B的域名跳转,而只能通过应用
A跳转到应用
B,要返回应用
A也只能从应用
B点击按钮跳转回应用
A。
SessionId共享登录状态这个思路是可取的。
根据这个思路,我们是否可以实现不通过点击按钮方式也能让浏览器自动带上SessionId
呢?
A登录后,直接在浏览器上修改域名访问系统
B时,系统
B检查到用户未登录后将请求重定向到系统
A,系统
A检查到请求从系统
B重定向过来,并且用户已经登录,那么可将
SessionId拼接到重定向链接上,再重定向回系统
B。系统
B获取到系统
A的
SessionId,然后根据
SessionId从
Redis查询用户信息,再写入系统
B的
Session中。如此就能实现自动携带
SessionId跳转。
SSO单点登录流程梳理如下:
SSO抽离为一个独立的应用,独立的域名,提供登录页面,要求其它应用不再提供登录页面,都必须通过
SSO登录。
session判断是否已经登录了,如果未登录则重定向到
SSO登录页面,并且在重定向链接带上是哪个应用跳转过来的,当用户在
SSO登录成功后重定向回原来的应用。
SSO登录页面时,浏览器会存储
SSO的
cookie,用户在
SSO登录成功后,
SSO存储用户的登录状态。
SSO生成一个
token,重定向回原应用,在重定向链接上带上
token。
token,这时需要访问
SSO验证
token并获取用户信息,
SSO验证成功后返回用户信息,原应用将用户信息存储到
Session中,验证成功后再重定向到首页。
B的域名访问应用
B,由于应用
B检查到
Session没有用户信息(未登录),于是重定向到
SSO应用。
SSO登录过了,重定向请求
SSO应用时浏览器会带上
cookie,所以
SSO应用发现用户已经登录,于是生成一个
token并重定向回应用
B。
B接收重定向请求,从请求中获取到
token,接着访问
sso应用验证
token并获取用户信息,在获取用户信息成功后再写入
Session,最后重定向到首页。
SSO
应用:
提供登录功能,支持从哪个应用重定向过来,登录成功后就重定向回哪个应用去;
提供根据
token
获取当前登录用户信息的接口。
未登录则重定向跳转到
SSO
,在跳转链接上带上登录成功后重定向调用的接口;提供给SSO重定向调用的接口,用于接收SSO传递的token,根据token从SSO获取登录用户信息,将用户信息写入Session,最后重定向到前端首页。
SDK的方式,尽可能将繁琐的步骤封装起来,让其它应用对接
SSO时仅需要依赖一个
jar包,并添加少量的配置。
SDK通过
Servlet提供的过滤器拦截所有请求:
1、如果请求是
“/checketSsoToken”
,则说明是用户在SSO
登录成功后(浏览器重定向)跳转过来的,并且会携带token
参数。此时SDK
需要请求SSO
检验token
,并将获取的用户信息写入Session
中,然后重定向到当前应用的前端首页。2、如果不是
“/checketSsoToken”
,则查看配置,判断当前请求是否不需要登录也可放行,如果是则放行,否则判断Session
中是否记录用户已经登录,如果未登录,则响应重定向,由前端跳转到SSO
登录。
ajax请求接口,后端判断未登录响应重定向无法真正重定向,所以要求前端拦截所有请求的响应,如果响应头有重定向标志,应从请求头获取重定向链接,然后让浏览器重定向。
3、如果是退出登录请求,则先清除应用自身缓存的用户登录信息,再重定向到
SSO
退出登录。
1、用户在浏览器中输入应用
A
的域名,要跳转到前端的index.html
页面;(nginx
反向代理配置实现)2、前端在首页调用一个后端接口,如获取菜单,触发校验登录(前端实现),未登录则拼接重定向链接,响应给前端,要求重定向到
SSO
登录页面(SDK
封装实现);3、用户在
SSO
登录成功后,由SSO
重定向调用应用A
的“/checketSsoToken”
。此url
在应用A
重定向到SSO
登录时作为参数拼接在URL
后面,由后端提供,前端只负责重定向;(SSO
应用实现)4、应用
A
请求SSO
的校验token
接口,并将响应的用户信息写入session
,重定向回前端首页。(SDK
封装实现)
需要注意的是,假设SSO设置的session过期时间为一个小时,如果用户在SSO登录后跳转回应用A,一个小时不操作后再跳转应用B,此时会因为SSO的session已经过期导致无法同步登录状态,用户就得要重新登录,所以SSO的session过期时间应该根据需要合理设置,不应该设置太短。
A退出登录时,只有应用
A和
SSO知道用户退出登录了,但其它应用却不得而知。
SSO之后,将其它应用的
Session过期时间配置尽可能短。又或者每次打开应用的首页都先跳转到SSO,如果已经登录,自然会重定向回来,这一个步骤对用户来说是透明的。
Shiro实现接口权限校验,也用了
Shiro的注解,所以权限校验的实现,我们在
SDK适配了
Shiro的注解,但完全弃用了
Shiro。





