@huynh
2016-03-24T00:43:13.000000Z
字数 8023
阅读 2794
cas 单点登录
- http://blog.csdn.net/small_love/article/details/6664831
- http://blog.163.com/zhao_jinggui/blog/static/169620429201411245344180/
- http://wenku.baidu.com/link?url=BtLcRAFd2__6mgE9PqCVrSMYeW_2fEXSNrHLAfDFwyRQEgZ3__Z_g8pFW9A2W53JIz_w7oonASNoaz9-mCjvgd3Pd-VrERWKU4fY8tmZJjK
- http://wenku.baidu.com/link?url=WO6TSit5NIvGJUrhIAwMbyF7OfWsDJnfbgcJq8tpfTtzA2Q3bvERMJNlrUdEXBLp1WQ7Rw1X_NvK9rK3YtDT0BWHLHhJ4dl8hW83pea0lw_
- http://blog.csdn.net/ahpo/article/details/46412859
- http://zxs19861202.iteye.com/blog/855856
- http://blog.csdn.net/haydenwang8287/article/details/5765941
修改WEB-INF/deployerConfigContext.xml
在id=proxyAuthenticationHandler的bean中增加属性p:requireSecure="false"
修改WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xml
在id=ticketGrantingTicketCookieGenerator的bean中修改属性p:cookieSecure="false"
修改WEB-INF/spring-configuration/warnCookieGenerator.xml
在id=warnCookieGenerator的bean种修改属性p:cookieSecure="false"
各项目/webapp/WEB-INF/web.xml
将casServerLoginUrl的参数值https改为http
<dependency><groupId>org.apache.openejb</groupId><artifactId>commons-dbcp-all</artifactId><version>1.3-r699049</version></dependency>
<dependency><groupId>commons-pool</groupId><artifactId>commons-pool&</artifactId><version>1.6</version></dependency>
1. 先创建一个bean,id随便,如下:
<bean id="**dbAuthHandler**"class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"><property name="dataSource" ref="dataSource"/><property name="sql" value="select password from user where name = ?"/></bean>
2. 将1创建的bean加入authenticationManager
将id=authenticationManager的bean中map值key=primaryAuthenticationHandler的改为key=自定义的bean,这个bean的class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler",原来的primaryAuthenticationHandler就不用了。
如下:
3. 创建dataSource的bean
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property><property name="url"><value>jdbc:mysql://127.0.0.1:3306/user</value></property><property name="username"><value>root</value></property><property name="password"><value>admin</value></property></bean>
参考http://blog.csdn.net/small_love/article/details/6664831
http://blog.csdn.net/yuwenruli/article/details/6600032
<!-- ======================== 单点登录开始 ======================== --><!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置 --><listener><listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class></listener><!-- 该过滤器用于实现单点登出功能,可选配置。 --><filter><filter-name>CAS Single Sign Out Filter</filter-name><filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class></filter><filter-mapping><filter-name>CAS Single Sign Out Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 该过滤器负责用户的认证工作,必须启用它 --><filter><filter-name>CASFilter</filter-name><filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class><init-param><param-name>casServerLoginUrl</param-name><param-value>http://localhost:8080/cas/login</param-value><!--这里的server是服务端的IP --></init-param><init-param><param-name>serverName</param-name><param-value>http://localhost:8080</param-value></init-param></filter><filter-mapping><filter-name>CASFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 该过滤器负责对Ticket的校验工作,必须启用它 --><filter><filter-name>CAS Validation Filter</filter-name><filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class><init-param><param-name>casServerUrlPrefix</param-name><param-value>http://localhost:8080/cas</param-value></init-param><init-param><param-name>serverName</param-name><param-value>http://localhost:8080</param-value></init-param></filter><filter-mapping><filter-name>CAS Validation Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 --><filter><filter-name>CAS HttpServletRequest Wrapper Filter</filter-name><filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class></filter><filter-mapping><filter-name>CAS HttpServletRequest Wrapper Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 --><filter><filter-name>CAS Assertion Thread Local Filter</filter-name><filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class></filter><filter-mapping><filter-name>CAS Assertion Thread Local Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- ======================== 单点登录结束 ======================== -->
<dependency><groupId>org.jasig.cas.client</groupId><artifactId>cas-client-core</artifactId><version>3.3.3</version></dependency>
CAS 系统中设计了 5 中票据: TGC 、 ST 、 PGT 、 PGTIOU 、 PT 。
Ø Ticket-granting cookie(TGC) :存放用户身份认证凭证的 cookie ,在浏览器和 CAS Server 间通讯时使用,并且只能基于安全通道传输( Https ),是 CAS Server 用来明确用户身份的凭证;这个是实现多系统只需登录一次的关键。
Ø Service ticket(ST) :服务票据,服务的惟一标识码 , 由 CAS Server 发出( Http 传送),通过客户端浏览器到达业务服务器端;一个特定的服务只能有一个惟一的 ST ;
Ø Proxy-Granting ticket ( PGT ):由 CAS Server 颁发给拥有 ST 凭证的服务, PGT 绑定一个用户的特定服务,使其拥有向 CAS Server 申请,获得 PT 的能力;
Ø Proxy-Granting Ticket I Owe You ( PGTIOU ) : 作用是将通过凭证校验时的应答信息由 CAS Server 返回给 CAS Client ,同时,与该 PGTIOU 对应的 PGT 将通过回调链接传给 Web 应用。 Web 应用负责维护 PGTIOU 与 PGT 之 间映射关系的内容表;
Ø Proxy Ticket (PT) :是应用程序代理用户身份对目标程序进行访问的凭证;

如上图: CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护 Web 应用的受保护资源,过滤从客户端过来的每一个 Web 请求,同 时, CAS Client 会分析 HTTP 请求中是否包含请求 Service Ticket( ST 上图中的 Ticket) ,如果没有,则说明该用户是没有经过认证的;于是 CAS Client 会重定向用户请求到 CAS Server ( Step 2 ),并传递 Service (要访问的目的资源地址)。 Step 3 是用户认证过程,如果用户提供了正确的 Credentials , CAS Server 随机产生一个相当长度、唯一、不可伪造的 Service Ticket ,并缓存以待将来验证,并且重定向用户到 Service 所在地址(附带刚才产生的 Service Ticket ) , 并为客户端浏览器设置一个 Ticket Granted Cookie ( TGC ) ; CAS Client 在拿到 Service 和新产生的 Ticket 过后,在 Step 5 和 Step6 中与 CAS Server 进行身份核实,以确保 Service Ticket 的合法性。
在该协议中,所有与 CAS Server 的交互均采用 SSL 协议,以确保 ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向 的过程。但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透明的(使用 HttpsURLConnection )。
时序图:

当用户访问另一个应用的服务再次被重定向到 CAS Server 的时候, CAS Server 会主动获到这个 TGC cookie ,然后做下面的事情:
1) 如果 User 持有 TGC 且其还没失效,那么就走基础协议图的 Step4 ,达到了 SSO 的效果;
2) 如果 TGC 失效,那么用户还是要重新认证 ( 走基础协议图的 Step3) 。
客户端消息流程
- 第一次访问http://localhost:8080/a,
CLIENT:没票据且SESSION中没有消息所以跳转至CAS
CAS:拿不到TGC故要求用户登录- 认证成功后回跳
CAS:通过TGT生成ST发给客户端,客户端保存TGC,并重定向到http://localhost:8080/a
CLIENT:带有票据所以不跳转只是后台发给CAS验证票据(浏览器中无法看到这一过程)- 第一次访问http://localhost:8080/b
CLIENT:没票据且SESSION中没有消息所以跳转至CAS
CAS:从客户端取出TGC,如果TGC有效则给用户ST并后台验证ST,从而SSO。【如果失效重登录或注销时,怎么通知其它系统更新SESSION信息呢??TicketGrantingTicketImpl类grantServiceTicket方法里this.services.put(id,service);可见CAS端已经记录了当前登录的子系统】- 再次访问http://localhost:8080/a
CLIENT:没票据但是SESSION中有消息故不跳转也不用发CAS验证票据,允许用户访问
自己理解
- 当浏览器首次访问系统A时,系统A会被cas拦截并重定向到cas/login页面进行登录验证,登录成功后会重定向到原来的页面,并且附带ticket和设置浏览器的cookie,key=CASTGC。系统A拿到ticket后会在后台再次将ticket发送到cas服务器进行验证,通过后即放行。
- 当浏览器再首次访问系统B时,系统B会被cas拦截并重定向到cas服务器,这个时候浏览器因为之前访问过系统A并且被cas设置了cookie(CASTGC),这时候cas服务器会自动获取CASTGC进行验证,通过后即放行,设置cookie为JSESSIONID。
总结
用户第一次访问一个CAS 服务的客户web 应用时(访问URL :http://192.168.7.90:8081/web1 ),部署在客户web 应用的cas AuthenticationFilter ,会截获此请求,生成service 参数,然后redirect 到CAS 服务的login 接口,url 为https://cas:8443/cas/login?service=http%3A%2F%2F192.168.7.90%3A8081%2Fweb1%2F,认证成功后,CAS 服务器会生成认证cookie ,写入浏览器,同时将cookie 缓存到服务器本地,CAS 服务器还会根据service 参数生成ticket,ticket 会保存到服务器,也会加在url 后面,然后将请求redirect 回客户web 应用,url为http://192.168.7.90:8081/web1/?ticket=ST-5-Sx6eyvj7cPPCfn0pMZuMwnbMvxpCBcNAIi6-20 。这时客户端的AuthenticationFilter 看到ticket 参数后,会跳过,由其后面的TicketValidationFilter 处理,TicketValidationFilter会利用httpclient 工具访问cas 服务的/serviceValidate 接口, 将ticket 、service 都传到此接口,由此接口验证ticket的有效性,TicketValidationFilter 如果得到验证成功的消息,就会把用户信息写入web 应用的session 里。至此为止,SSO 会话就建立起来了,以后用户在同一浏览器里访问此web 应用时,AuthenticationFilter 会在session 里读取到用户信息,所以就不会去CAS 认证,如果在此浏览器里访问别的web 应用时,AuthenticationFilter在session 里读取不到用户信息,会去CAS 的login 接口认证,但这时CAS 会读取到浏览器传来的cookie ,所以CAS 不会要求用户去登录页面登录,只是会根据service 参数生成一个ticket ,然后再和web 应用做一个验证ticket 的交互而已。