CAS單點登陸的原理

1.什麼是CAS?

CAS ( Central Authentication Service ) 是 Yale 大學發起的一個企業級的、開源的項目,旨在爲 Web 應用系統提供一種可靠的單點登錄解決方法(屬於 Web SSO )。
CAS 開始於 2001 年, 並在 2004 年 12 月正式成爲 JA-SIG 的一個項目。

2.術語解釋

2.1 單點登陸

對於兩個相互獨立的系統A、B,如果已經登陸了系統A,在訪問系統B時不需要再次登陸,這就是單點登陸。

比如我們登陸了QQ,打開QQ空間或QQ郵箱時就不要再輸入用戶名和密碼再次登陸了,這就是單點登陸。

2.2 Service Ticket

Service ticket(ST) :服務票據,服務的惟一標識碼 , 由 CAS Server 發出(Http 傳送),通過客戶端瀏覽器到達業務服務器端;一個特定的服務只能有一個惟一的 ST.

ST是由CAS服務器生成,並傳遞給客戶端,客戶端再使用這個ST向CAS服務器驗證身份,驗證通過後客戶端就通過CAS服務器的身份驗證,也就可以創建session了。

ST會保存在CAS服務器中的ConcurrentHashMap,並且可以設置有效期,默認有效期是10秒,可以在配置文件spring-configuration/ticketExpirationPolicies.xml中修改。

<bean id="serviceTicketExpirationPolicy" class="org.jasig.cas.ticket.support.MultiTimeUseOrTimeoutExpirationPolicy"
          c:numberOfUses="1" c:timeToKill="${st.timeToKillInSeconds:10}" c:timeUnit-ref="SECONDS"/>

2.3 Ticket Granting ticket

Ticket Granting ticket(TGT) :票據授權票據,由 KDC 的 AS 發放。即獲取這樣一張票據後,以後申請各種其他服務票據 (ST) 便不必再向 KDC 提交身份認證信息 (Credentials) 

TGT由CAS服務器生成,保存在CAS服務器中的ConcurrentHashMap,並且存放到客戶端的瀏覽器的cookie的參數CASTGC中,可以在配置文件spring-configuration/ticketGrantingTicketCookieGenerator.xml中修改。

<bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
		p:cookieSecure="false"
		p:cookieMaxAge="-1"
		p:cookieName="CASTGC"
		p:cookiePath="/cas" 
		p:rememberMeMaxAge="43200" />
TGT也可以設置超時時間,默認有效期是8個小時,可以在文件spring-configuration/ticketExpirationPolicies.xml中修改。
<bean id="grantingTicketExpirationPolicy" class="org.jasig.cas.ticket.support.TicketGrantingTicketExpirationPolicy"
          p:maxTimeToLiveInSeconds="${tgt.maxTimeToLiveInSeconds:28800}"
          p:timeToKillInSeconds="${tgt.timeToKillInSeconds:7200}"/>

CAS的單點登陸就是使用這個TGT來實現。

3.系統部署情況

本人使用的CAS源碼包是4.0.0版本的,可以到網上下載CAS的源碼包cas-server-4.0.0-release.zip

3.1 首先配置三臺tomcat,它們的安裝信息如下:

(1)tomcat1 

端口號:8080

部署的WAR包:cas-server-webapp-4.0.0.war

可以將這個WAR包改成名cas.war


(2)tomat2

端口號:8081

部署的WAR包:buyer_center.war

web.xml中的內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:applicationContext-servlet.xml
		</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<filter>
		<filter-name>encoding-filter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>encoding-filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<servlet>
		<servlet-name>annomvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:applicationContext-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>annomvc</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

	<filter>
		<filter-name>CAS Authentication Filter</filter-name>
		<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
		<init-param>
			<param-name>casServerLoginUrl</param-name>
			<param-value>http://login.mycompany.com:8080/cas/login</param-value>
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
			<param-value>http://buyer.mycompany.com:8081</param-value>
		</init-param>
	</filter>
	
	<filter>
		<filter-name>CAS Validation Filter</filter-name>
		<filter-class>org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>
		<init-param>
			<param-name>casServerUrlPrefix</param-name>
			<param-value>http://login.mycompany.com:8080/cas</param-value>
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
			<param-value>http://buyer.mycompany.com:8081</param-value>
		</init-param>
		<init-param>
			<param-name>redirectAfterValidation</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	
	<filter>
		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
		<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
	</filter>
	
	<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 Authentication Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>CAS Validation Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>CAS Assertion Thread Local Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

</web-app>

applicationContext-servlet.xml中的內容如下:

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
       default-lazy-init="true">
	<mvc:annotation-driven/>
	<context:component-scan base-package="com.controller"/>
	<mvc:default-servlet-handler/>
       
</beans>

(3)tomcat3

端口號:8083

部署的WAR包:seller_center.war

web.xml中的內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:applicationContext-servlet.xml
		</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<filter>
		<filter-name>encoding-filter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>encoding-filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<servlet>
		<servlet-name>annomvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:applicationContext-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>annomvc</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

	<filter>
		<filter-name>CAS Authentication Filter</filter-name>
		<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
		<init-param>
			<param-name>casServerLoginUrl</param-name>
			<param-value>http://login.mycompany.com:8080/cas/login</param-value>
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
			<param-value>http://seller.mycompany.com:8083</param-value>
		</init-param>
	</filter>
	
	<filter>
		<filter-name>CAS Validation Filter</filter-name>
		<filter-class>org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>
		<init-param>
			<param-name>casServerUrlPrefix</param-name>
			<param-value>http://login.mycompany.com:8080/cas</param-value>
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
			<param-value>http://seller.mycompany.com:8083</param-value>
		</init-param>
		<init-param>
			<param-name>redirectAfterValidation</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	
	<filter>
		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
		<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
	</filter>
	
	<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 Authentication Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>CAS Validation Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>CAS Assertion Thread Local Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

</web-app>

applicationContext-servlet.xml中的內容如下:

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
       default-lazy-init="true">
	<mvc:annotation-driven/>
	<context:component-scan base-package="com.controller"/>
	<mvc:default-servlet-handler/>
       
</beans>

3.2 配置HOST文件中的域名

127.0.0.1       login.mycompany.com
127.0.0.1       seller.mycompany.com
127.0.0.1       buyer.mycompany.com

4.CAS實現單點登陸的原理

4.1 訪問buyer

buyer.mycompany.com:8081/buyer_center/loginController/login.do

4.2 跳轉到CAS登陸頁面,並且將訪問的URL放到CAS跳轉參數service中

http://login.mycompany.com:8080/cas/login?service=http%3A%2F%2Fbuyer.mycompany.com%3A8081%2Fbuyer_center%2FloginController%2Flogin.do


4.3 登陸

輸入用戶名和密碼後就登陸到CAS中,登陸成功後CAS會創建一個Ticket Granting ticket(TGT) ,把它保存在DefaultTicketRegistry中的

Map<String, Ticket> cache = new ConcurrentHashMap<String, Ticket>();
並且CAS服務器也會將這個TGT保存到客戶端的瀏覽器的cookie中.

登陸成功後輸入:http://login.mycompany.com:8080/cas/login,可以看到TGT。


4.4 CAS登陸成功後跳轉service的地址,並且附帶一個Service Ticket

buyer.mycompany.com:8081/buyer_center/loginController/login.do?ticket=ST-12-Mfq4OVkBAlddDyx1ucRq-cas01.example.org

客戶端buyer_center會去拿到這個ST,並且發送HTTP請求到CAS中去驗證,驗證通過後客戶端就會創建session,並且跳轉到

buyer.mycompany.com:8081/buyer_center/loginController/login.do

這樣就完成了登陸。

4.5 單點登陸

前面4步已經完成了系統buyer_center的登陸,下面將介紹單點登陸到seller_center的過程。

(1)訪問另一系統seller_center

http://seller.mycompany.com:8083/seller_center/loginController/login.do

客戶端seller_center的攔截器AuthenticationFilter攔截到當前訪問沒有session,攔截器Cas10TicketValidationFilter攔截到當前URL沒有ST,所以轉發到CAS登陸URL。

http://login.mycompany:8080/cas/login?service=http%3A%2F%2Fseller.mycompany.com%3A8083%2Fseller_center%2FloginController%2Flogin.do

(2)CAS服務器會去讀取cookie TGT

CAS 服務器會去讀取域名login.mycompany.com下的cookie變量CASTGC(裏面存放着TGT的值).

CAS服務器會去驗證這個TGT是否合法,如果合法,則會創建一個ST並且返回

http://seller.mycompany.com:8083/seller_center/loginController/login.do?ticket=ST-12-Mfq4OVkBAlddDyx1ucRq-cas01.example.org


(3)驗證ST合法性

客戶端seller_center拿到這個ST後,就會向CAS服務器發送一個HTTP請求,驗證ST的合法性,如果合法,則創建一個session.

這樣seller_center不需要登陸就完成了單點登陸。

5.CAS實現單點登出的原理

 後續...

6.總結

6.1 CAS是比較成熟的單點登陸解決方案

6.2 CAS性能很差,單臺機的併發量只有十幾個

6.2 CAS在實際項目的應用中需要做大量的定製開發,需要修改很多源碼,會佔用開發人員大量的時間和精力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章