在上一篇文章git
如何设计一个单点登陆系统(2)?github
中主要讲解了可跨域SSO系统服务端,客户端在登陆,登出过程当中分别应该承担的职责,本文将重点聊一下具体技术实现,源码地址: https://github.com/zhoudapeng/zssoredis
首先聊服务端的实现,毕竟服务端是整个单点登陆系统的大脑spring
提供登陆页,这个是登陆的基础,全部的接入方在发现当前用户未登陆的状况下都会重定向到sso服务端的登陆页,服务端的逻辑以下:跨域
sso服务端登陆页逻辑缓存
这里服务端须要作个判断:cookie
若是当前登陆存在.sso.com域下的有效cookie,则证实此用户以前在其余业务系统登陆过,此时无需再让用户登陆,只须要绑定token与此系统名的关系,而后重定向到此系统的回调接口(接入方须要在此回调接口中验证token,建立本地会话)分布式
不存在.sso.com域下的有效cookie,证实此用户未登陆过,须要跳转到登陆页,让用户登陆,为了用户登陆后能直接进入以前的页面,这里重定向的过程当中须要带上redirectUrl 这个参数post
2.提供登陆接口,用户在登陆页输入帐号密码后会经过form表单已post的形式提交到此接口优化
sso服务端登陆form表单提交处理逻辑
若是帐号密码不对,则再次跳转到登陆页
帐号密码匹配,则须要建立token,绑定token与系统名的关系,写全局cookie,而后重定向到接入方的回调地址
3.提供验证token接口
sso服务端验证token接口
token不存在,返回验证失败
token存在,则取出token的有效截止日期,并绑定token与系统名的关系
4.提供登出接口
sso服务端登出接口
登出时,须要根据token查到全部绑定过的系统名,而后调用各个系统的登出接口一一登出。
以上是服务端须要提供的4个接口,下面咱们再将一下客户端的实现
在第一篇文章中讲过,一个好的sso系统必需要让接入方接入简单,因此本人借鉴了spring auto-driven的思想,也提供了对应的命名空间,并抽象出了UrlHelper,UserStore,ZssoClient,ZssoConfigResolver4个组件,以及默认实现类,接入方在接入过程当中能够随意拓展这4个组件,而后直接注入到业务层上下文便可。
UrlHelper:拼接url的组件,如无特殊需求不建议从新实现
ZssoClient:跟服务端交互的组件,如无特殊需求不建议从新实现
ZssoConfigResolver:解析配置文件的组件,默认实现是读取本地classpath下zsso-client.properties配置文件,如无特殊需求不建议从新实现
UserStore:存取用户信息的组件,包括根据token解析用户信息,绑定token与userId关系,解绑token,默认实现只是为了演示用,接入方请务必本身实现此接口,并以userStore的名称注入到业务层上下文中。
拓展组件使用方式:
拓展UserStore组件配置方式
在spring扫描掉<zsso:auto-driven/>时会去回调ZssoNamespaceHandler的init方法,最终执行ZssoBeanDefinitionParser的parse方法,在此方法中会去检查每一个组件是否有注入对应的BeanDefinition,若是没有则会自动注入默认实现类,核心代码以下:
ZssoBeanDefinitionParser核心代码
ComponentInitializer核心代码
至此组件初始化的问题已经解决了,另外须要接入方开发的是以下问题:
判断登陆状态
登陆成功回调接口(包括check token的逻辑)
登出回调接口
既然每一个接入方都有这样的共性,因此我提供了一个ZssoFilter,在Filter里根据不一样的url作不一样的处理,接入方只须要配置此Filter便可,Filter内部会自动去获取组件,接入方只须要拓展相关组件便可,ZssoFilter核心代码以下:
ZssoFilter核心逻辑
LoginCallbackFilter已封装好解析请求参数中token,check token,建立本地会话,跳转到原页面等功能
LoginCheckFilter已封装好判断当前用户是否登陆及跳转到登陆页的逻辑
LogoutFilter已封装好删除本地会话的功能
代码中不少代码都是演示类的,尤为是server端的实现,好比保持用户信息都是存的本地缓存,若是要放到生成环境则须要优化下这块的逻辑,好比放到redis这样的分布式缓存等等。
最后很是感谢你们能在百忙中抽空看个人文章,你们的每一次查看都是我继续写文章的动力,因为本人是典型理科男,文笔可能欠妥,但愿你们可以继续支持我,我也会继续努力,继续坚持原创,希望能让你们都能有所收获!