概念

SSO: Single sign-on 一系列相关但独立的系统之间的访问控制属性。通过支持该属性,用户可以使用一个用户ID和密码登录到相关联的系统或者无缝的登录到各系统。(维基百科 麦子译)

简单说就是在一处登陆就可以访问一系列相关的系统

CAS:作为项目:apereo基金会下的一个项目,提供企业级SSO解决方案;作为协议:a simple and powerful ticket-based protocol developed exclusively for (PROEJCT) CAS.

原理

1.总体架构

既然解决的是单点登录的问题,那么就会存在一堆需要单点登录的应用。CAS的解决方案中,登陆这件事情被集中放在统一的登陆服务上处理,各个应用将用户引导到这个服务去处理,处理完之后再跳回本应用。为此,各个应用需要具备识别是否登陆、引导用户跳转、接受等候跳转的功能。这些功能都是重复的,所以考虑到每个应用包含一个客户端来处理。

另一方面,作为一个流行的单点登录解决方案,需要考虑支持多种协议多种客户端各种验证方式等等。

所以就有了以下这张架构图:

cas_architecture

2.大体流程

关于单点登陆的流程官方的流程图已经非常能够说明问题了。需要的是一点耐心和细心

解释下图中角色:User=用户,Browser=浏览器,CAS Server=负责登录的服务端,Protected APP = 一个需要单点登录的应用,Protected App #2=另一个需要单点登录的应用,区别在于,图中演示的第一步是需要用户输用户名密码登录到第一个应用,之后登录APP #2是不需要用户输用户名密码的,直接按照协议系统自动登录。

再解释下cas协议定义或者使用到的几个关键概念:

  • Service Ticket(ST) 代表一个用户被授权使用某个应用(用户王大萌 被授权可以使用收银台应用)
  • Ticket Granting Ticket (TGT) 代表一个已经信任登陆过了的用户,第二次登录的时候,用户不需要输密码,系统会验证请求中的TGT来识别用户是否登录
  • Ticket Granting Cookie(TGC) 本地存储TGT的Cookie
  • 302 http状态码,根据http协议浏览器会自动跳转到响应回的地址

下面请仔细研读以下官方图表。英文看不懂请自行问翻译软件。

cas原理图

好的,如果你实在费劲,可以看这个简化版的。

cas大致流程图

解释下(括号中表示上图的步骤):

用户一定是首先访问内容,所以会首先访问一个应用也就是cas-client(1.),当访问的是受保护的内容时就需要登录,那么cas-client就会拦截并且将用户通过302跳转(2.)到cas-server,cas-server负责提供登录页面并验证用户是否靠谱(3.)。如果通过则跳转回应用并带上ST(4.),应用收到这个请求就会发起内部一个http请求给cas-server,问它这个ST是你给的吗?(5.),如果ST验证通过则cas-server会回执用户信息给应用(6.)。

事实上,后续流程是应用就会响应给浏览器sessionId,之后的请求都认为是登录过后的了。

请再回到官方的flow-diagram细致看下流程。确保你已经了解了整个流程。

技术

这里简单复习和介绍下cas涉及到的几个基本概念,以帮助我们更清晰更细节的明白其中的过程。

http协议是无状态的,也就是意味着一次连接过后,它就会把一切忘掉,下次再来服务器就不认识客户端了。但是实际上服务端是需要识别用户以提供不同的服务的,这个就催生了cookie。

cookie,小曲奇饼,下午餐佳品。是存储在客户端的一个小片段内容。

  • 使用HTTP的Set-Cookie消息头,Web服务器可以指定存储一个cookie
  • 当一个cookie存在,并且可选条件允许(没有过期,本域名…)的话,该cookie的值会在接下来的每个请求中被发送至服务器。cookie的值被存储在名为Cookie的HTTP消息头中,并且只包含了cookie的值,其它的选项全部被去除。

大致来说,服务器在http 响应头中set-cookie消息头后,浏览器创建一个cookie,cookie自带一些条件,最基本是哪个域名,如果达到域名,那就不管三七二十一后续的每次请求都带上这个cookie。也就是个参数回传的概念。

Session

http协议是无状态的,也就是意味着一次连接过后,它就会把一切忘掉,下次再来服务器不认识客户了。那咋办?cookie啊。cookie是工具,支持你回传参数,但是具体是啥参数呢?为了保持用户访问,一定会通过cookie回传一个识别用户的id。而在服务端,一定需要一个空间来存储用户的操作相关信息。接收到回传后需要识别这个id并将相关信息存储在这个空间里。这就是session。

An HTTP session is a sequence of network request-response transactions.

维基百科

所以session有以下特点:

  • http的无状态性,服务器识别客户端及其行为
  • 一般通过cookie保存
  • 服务器端存储
HTTP Status Code 302

这个状态码大致意思就是浏览器根据响应重发请求到新地址。 302跳转

Spring Web Flow(SWF)

Spring的一个子项目,简化复杂web页面流程的操作,比如,航空订票流程。基本上来说是一个基于web的轻量级流程引擎。

我们需要注意以下几个点

  • 与spring mvc 结合,通过配置可以将某个request会被映射给swf来处理
  • Xml形式的流程定义
  • State,流程定义语言的主要元素
    • Action State 某个后台处理
    • View State 显示一个页面
    • Subflow State 子流程
    • Decision State 根据某个表达式计算得出跳转选项
    • End State 结束

实现

了解了以上cas协议和基本概念之后,我们来看下代码。手上的代码是之前的兄弟checkout出来一直在维护的。最新的代码可以看cas的代码仓库 。基本的东西应该都是一致的。

主要的配置文件:

  • swf配置文件:env\ login-webflow.xml,登录流程的SWF定义
  • mvc配置文件: cas-servlet.xml 系统性配置,包括SWF与spring集成的配置,各个Controller的bean定义等
  • spring配置文件: deployerConfigContext.xml 部分核心业务组件的配置

登录流程解析:

  1. boss-starter : com.yiji.boot.boss.BOSSAutoConfiguration#marmotFilterProxyBean 启动阶段组装相关配置参数到marmot-client
  2. cas-client : com.yjf.marmot.filter.MarmotAuthenticationFilter#doFilter 拦截检测到未登录则跳转到登录页面 (http://{marmotUrl}/login)
  3. cas-server: cas-servlet.xml:130 login请求被映射到swf处理;login-webflow.xml 按照登录流程执行相关操作,加载登录页面(viewLoginForm),用户登录触发submit事件继续登录操作,最后redirect并写入st

组件:

  • org.jasig.cas.CentralAuthenticationService 单点登录核心处理
  • org.jasig.cas.authentication.AuthenticationManager 验证登录凭据的流程调度,marmot使用的是org.jasig.cas.authentication.AuthenticationManagerImpl
  • org.jasig.cas.authentication.handler.AuthenticationHandler 具体处理验证的验证组件
  • org.jasig.cas.authentication.principal.Service 代表需要单点登录的应用
  • org.jasig.cas.authentication.principal.Credentials凭证,登录信息
  • org.jasig.cas.ticket.Ticket 票根,st,tgt都继承自它,用户端(浏览器)使用cookie存储,服务端使用缓存(redis)存储,单点登录的核心就是验证两者是否相同
  • org.jasig.cas.ticket.registry.TicketRegistry 票根注册,存储票根,支持各种存储方式,比如内存中concurrentHashMap,缓存,数据库等

如果映射到我们通用的开发模式来看, Service、Credentials、Ticket属于模型(DO),TicketRegistry属于数据存储服务(DAO或者Repositroy),AuthenticationHandler、AuthenticationManager、CentralAuthenticationService 属于业务处理服务(Service或者Manager)

核心的代码请配合login-webflow.xml 文件的流程定义和CentralAuthenticationService来看代码,需要一点耐心和细心。

总结

任何一个协议主要都是给机器和系统玩儿的。所以学习cas的原理及实现,最需要的耐心。就是一个流程而已,重复看几遍就会懂。代码阅读方面,建议结合可运行的项目来看,需要的是耐心和细心。还需要结合cas协议的原来图来讲代码串联起来。


参考资料:

cas:

项目首页:https://apereo.github.io/cas/

代码仓库:https://github.com/apereo/cas

apereo基金会:https://www.apereo.org/

cookie:

http://blog.csdn.net/leo777/article/details/1780299

http://www.dannysite.com/blog/77/

https://www.w3.org/Protocols/rfc2109/rfc2109

session:

http://lelglin.iteye.com/blog/1906588

http 3xx:

https://www.w3.org/Protocols/HTTP/1.1/rfc2616bis/draft-lafon-rfc2616bis-latest.html#status.3xx

swf:

http://www.ibm.com/developerworks/cn/education/java/j-spring-webflow/

http://www.cnblogs.com/limeiky/p/5275303.html