上篇我们引入了SSO这个话题。本篇我们一步步深入分析SSO实现机理,并亲自动手实现一个线上可用的SSO认证服务器。
首先,我们来分析下单Web应用系统登录登出的实现机理。Web系统登录登出功能,通常属于系统安全管理模块的一部分。如上篇所说,登录,意味着用户与系统之间的一次会话开始,登出,意味着本次会话的结束。
下图列出整个登录登出会话过程中,用户与系统之间的HTTP交互过程:
如图,服务器内部又做了哪些工作呢?
通常服务端在用户登录请求到来时(圈1),会先做认证(Authentication)操作,就是证明这个浏览器请求用户是合法系统用户,一般情况就是验证用户名和密码。
认证通过后,系统紧接着给这个合法用户授权(Authorization),就是根据该用户在此系统中的权限定义,绑定正确的权限信息,为用户后续正确使用系统功能提供安全保障。
最后建立会话,这个可以基于服务器容器提供的Session机制或自己基于Cookie开发的类似功能,建立起本次会话。
登录成功后,当浏览器后续请求来时(圈2),服务器需进行登录状态判断,即判别是否处于会话状态,从而识别操作是否是本次登录用户的操作。
登出时,服务端取消会话,本次登录用户会话结束。下次请求时,系统即判断是非登录用户。
上面分析了单Web应用登录登出实现机理。那对于多系统的SSO,该如何实现呢?我们先分析下基本实现思路。
有上面分析可知,单Web应用登录,主要涉及到认证、授权、会话建立、取消会话等几个关键环节。推广到多系统,每个系统也会涉及到认证、授权、会话建立取消等工作。那我们能不能把每个系统的认证工作抽象出来,放到单独的服务应用中取处理,是不是就能解决单点登录问题?
思考方向是正确的,我们把这个统一处理认证服务的应用叫认证中心。当用户访问子系统需要登录时,我们把它引到认证中心,让用户到认证中心去登录认证,认证通过后返回并告知系统用户已登录。当用户再访问另一系统应用时,我们同样引导到认证中心,发现已经登录过,即返回并告知该用户已登录。
由上图可以看出,原先在各系统中的认证模块,已经剥离出来放到独立的认证中心中去执行。至于授权,每个应用都不一样,可维持原样。会话部分,其实分解成了全局会话和局部会话,这个后面再详细解释。
思路是有了,但真正实现这一认证服务器我们还得要具体解决几个关键问题
一、登录信息传递问题
应用系统将登录请求转给认证中心,这个很好解决,我们一个HTTP 301重定向即可实现。现在的问题是,用户在认证中心登录后,认证中心如何将消息转回给该系统?
这是在单web系统中不存在的问题。我们知道HTTP协议传递消息只能通过请求参数方式或cookie方式,cookie跨域问题不能解决,我们只能通过URL请求参数。
我们可以将认证通过消息做成一个令牌(token)再利用HTTP 301重定向传递给应用系统。但现在的关键是:该系统如何判断这个令牌的真伪?如果判断这个令牌确实是由认证中心发出的,且是有效的?
我们还需要应用系统和认证中心之间再来个直接通信,来验证这个令牌确实是认证中心发出的,且是有效的。由于应用系统和认证中心是属于服务端之间的通信,不经过用户浏览器,相对是安全的。
用户首次登录时流程如下:
1.用户浏览器访问系统A需登录受限资源。
2.系统A发现该请求需要登录,将请求重定向到认证中心,进行登录。
3.认证中心呈现登录页面,用户登录,登录成功后,认证中心重定向请求到系统A,并附上认证通过令牌。
4.系统A与认证中心通信,验证令牌有效,证明用户已登录。
5.系统A将受限资源返给用户。
已登录用户首次访问应用群中系统B时:
1. 浏览器访问另一应用B需登录受限资源。
2. 系统B发现该请求需要登录,将请求重定向到认证中心,进行登录。
3. 认证中心发现已经登录,即重定向请求响应到系统B,附带上认证令牌。
4. 系统B与认证中心通信,验证令牌有效,证明用户已登录。
5. 系统B将受限资源返回给客户端。
二、登录状态判断问题
用户到认证中心登录后,用户和认证中心之间建立起了会话,我们把这个会话称为全局会话。当用户后续访问系统应用时,我们不可能每次应用请求都到认证中心去判定是否登录,这样效率非常低下,这也是单Web应用不需要考虑的。
我们可以在系统应用和用户浏览器之间建立起局部会话,局部会话保持了客户端与该系统应用的登录状态,局部会话依附于全局会话存在,全局会话消失,局部会话必须消失。
用户访问应用时,首先判断局部会话是否存在,如存在,即认为是登录状态,无需再到认证中心去判断。如不存在,就重定向到认证中心判断全局会话是否存在,如存在,按1提到的方式通知该应用,该应用与客户端就建立起它们之间局部会话,下次请求该应用,就不去认证中心验证了。
三、登出问题
用户在一个系统登出了,访问其它子系统,也应该是登出状态。要想做到这一点,应用除结束本地局部会话外,还应该通知认证中心该用户登出。
认证中心接到登出通知,即可结束全局会话,同时需要通知所有已建立局部会话的子系统,将它们的局部会话销毁。这样,用户访问其它应用时,都显示已登出状态。
整个登出流程如下:
1.客户端向应用A发送登出Logout请求。
2.应用A取消本地会话,同时通知认证中心,用户已登出。
3.应用A返回客户端登出请求。
4.认证中心通知所有用户登录访问的应用,用户已登出。
到此,我们完整介绍了实现一个SSO认证服务器的基本思路方法,后面我们就按照这个方法,自己动手利用Java一步步实现一个SSO认证服务器。
未完待续读完本篇,你应该了解如下内容:1.登录属于系统安全管理模块一部分,涉及认证、建立会话、会话状态判断、取消会话等操作。
2.剥离各系统认证功能,建立统一独立认证服务中心,是解决SSO问题的正确方法。
3.由于是分布式,处理SSO需要解决认证消息传递问题、登录状态判断问题、登出消息传递问题,保证各应用系统与认证中心之间有效通信。
Java架构师干货、有料,不一样的Java技术实名社群微信号:java-architect
[ 原创声明:Java架构师尊重原创作者及单位版权,本文为Java架构师原创内容, 作者:常明,转载请注明出处 ]