1. 程式人生 > >CAS實現單點登入(SSO)

CAS實現單點登入(SSO)

什麼是單點登入

單點登入(Single Sign On),簡稱為 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,使用者只需要登入一次就可以訪問所有相互信任的應用系統。 我們目前的系統存在諸多子系統,而這些子系統是分別部署在不同的伺服器中,那麼使用傳統方式的session是無法解決的,我們需要使用相關的單點登入技術來解決。 它的實現思路如下圖: 在這裡插入圖片描述 當用戶訪問系統1時,系統1發現使用者沒有登入,會跳轉到認證系統,在認證系統中實現登入,並且返回一個票據ticket給客戶端,之後,當用戶再要訪問其他的系統時,可以帶著ticket去訪問,其他的系統通過和認證系統進行ticket驗證,如果驗證通過,就不需要再進行登入。

什麼是CAS

CAS 是 Yale 大學發起的一個開源專案,旨在為 Web 應用系統提供一種可靠的單點登入方法。他的特點是: 【1】開源的企業級單點登入解決方案。 【2】CAS Server 為需要獨立部署的 Web 應用。 【3】CAS Client 支援非常多的客戶端(這裡指單點登入系統中的各個 Web 應用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。 從結構分析來說,CAS包含兩個部分:CAS Server 和 CAS Client。CAS Server 需要獨立部署,主要負責對使用者的認證工作;CAS Client 負責處理對客戶端受保護資源的訪問請求,需要登入時,重定向到 CAS Server。下圖是 CAS 最基本的協議過程: 在這裡插入圖片描述

SSO單點登入訪問流程主要有以下步驟:

  1. 訪問服務:SSO客戶端傳送請求訪問應用系統提供的服務資源。
  2. 定向認證:SSO客戶端會重定向使用者請求到SSO伺服器。
  3. 使用者認證:使用者身份認證。
  4. 發放票據:SSO伺服器會產生一個隨機的Service Ticket。
  5. 驗證票據:SSO伺服器驗證票據Service Ticket的合法性,驗證通過後,允許客戶端訪問服務。
  6. 傳輸使用者資訊:SSO伺服器驗證票據通過後,傳輸使用者認證結果資訊給客戶端。
CAS服務端部署

Cas服務端其實就是一個war包,可以直接部署在tomcat中執行,這裡提供一個Cas的war包 連結:https://pan.baidu.com/s/1LzEb-wtH7YCO8MdQw4q7bA

提取碼:lc1n 下載後解壓sourse目錄下的壓縮包,然後進入裡面的modules目錄,下面有一個cas-server-webapp-4.0.0.war,這個就是Cas服務端的war包。 將這個war改名為cas.war,放入tomcat的webapps下,啟動tomcat,就可以自動解壓這個war包,訪問http://localhost:9100/cas(我這裡修改了tomcat的埠),就可以進入cas的登入頁面

注意:因為修改了tomcat的啟動埠為:9100,所以應該把cas的配置也進行修改

開啟cas的WEB-INF/cas.properties,修改server.name=http://localhost:9100 在這裡插入圖片描述 這個頁面是cas預設的登入頁面,後續可以自己更改這個登入頁面。 這裡有個固定的使用者名稱/密碼:casuser /Mellon 登入成功後: 在這裡插入圖片描述 這個使用者名稱和密碼是cas服務預設固定的,也可以自己新增一些登入使用者,進入webapps下的解壓後的cas目錄,開啟WEB-INF中deployerConfigContext.xml,新增使用者名稱密碼 在這裡插入圖片描述

去除https認證

CAS預設使用的是HTTPS協議,如果使用HTTPS協議需要SSL安全證書(需向特定的機構申請和購買) 。如果對安全要求不高或是在開發測試階段,可使用HTTP協議。我們這裡講解通過修改配置,讓CAS使用HTTP協議。

  1. 修改cas的WEB-INF/deployerConfigContext.xml 在這裡插入圖片描述
  2. 修改cas的/WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xml 在這裡插入圖片描述 引數p:cookieMaxAge="-1",是COOKIE的最大生命週期,-1為無生命週期,即只在當前開啟的視窗有效,關閉或重新開啟其它視窗,仍會要求驗證。可以根據需要修改為大於0的數字,比如3600等,意思是在3600秒內,開啟任意視窗,都不需要驗證。
  3. 修改cas的WEB-INF/spring-configuration/warnCookieGenerator.xml 在這裡插入圖片描述
CAS客戶端入門小Demo

使用maven搭建一個客戶端工程1,完成之後,引入依賴,指定tomcat啟動埠為8080

<dependencies>
	<!-- cas -->
	<dependency>
		<groupId>org.jasig.cas.client</groupId>
		<artifactId>cas-client-core</artifactId>
		<version>3.3.3</version>
	</dependency>
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>servlet-api</artifactId>
		<version>2.5</version>
		<scope>provided</scope>
	</dependency>
</dependencies>
<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>2.3.2</version>
			<configuration>
				<source>1.7</source>
				<target>1.7</target>
			</configuration>
		</plugin>
		<plugin>
			<groupId>org.apache.tomcat.maven</groupId>
			<artifactId>tomcat7-maven-plugin</artifactId>
			<configuration>
				<!-- 指定埠 -->
				<port>8080</port>
				<!-- 請求路徑 -->
				<path>/</path>
			</configuration>
		</plugin>
	</plugins>
</build>

修改web.xml,這個是使用原生的cas客戶端最重要的配置

<?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">

	<!-- =========================單點登入功能開始=================================== -->

	<!-- 用於單點退出 監聽器,該過濾器用於實現單點登出功能,(當一個系統退出登入後,其他的系統也都隨之退出)(可選配置) -->
	<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>
			<!-- 這裡配置cas服務的訪問地址,用於當用戶未登入被攔截後,跳往cas的登入頁面 -->
			<param-value>http://localhost:9100/cas/login</param-value>
			<!--這裡的server是服務端的IP -->
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
			<!-- 這裡配置使用者當前實際要訪問的地址,因為當在cas登入成功後,需要重定向到之前的頁面,也就是被攔截的頁面 -->
			<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>
			<!-- 這裡配置cas服務的訪問地址,用於當用戶未登入被攔截後,跳往cas的登入頁面 -->
			<param-value>http://localhost:9100/cas</param-value>
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
			<!-- 這裡配置使用者當前實際要訪問的地址,因為當在cas登入成功後,需要重定向到之前的頁面,也就是被攔截的頁面 -->
			<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>

	<!-- =========================單點登入功能結束=================================== -->

</web-app>

為了可以在頁面看到效果,這裡建立一個簡單的jsp檔案

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登入成功1</title>
</head>
<body>
	
	<!-- request.getRemoteUser()為在web.xml中配置的一個過濾器,獲取遠端登入名 -->
	
	<h1>1,登入成功,</h1>歡迎你,<%=request.getRemoteUser() %>
</body>
</html>

因為要測試單點登入的功能,所以,至少需要兩個系統,這裡再使用maven搭建一個客戶端工程2,完成之後,引入依賴,指定tomcat啟動埠為8081 pom.xml檔案中引入的依賴相同,只是需要在tomcat外掛那裡把啟動埠改成8081

<plugin>
	<groupId>org.apache.tomcat.maven</groupId>
	<artifactId>tomcat7-maven-plugin</artifactId>
	<configuration>
		<!-- 指定埠 -->
		<port>8080</port>
		<!-- 請求路徑 -->
		<path>/</path>
	</configuration>
</plugin>

web.xml中的配置也基本相同,只是需要把當前訪問的地址改成localhost:8081

<!-- 該過濾器負責使用者的認證工作,必須啟用它 -->
<filter>
	<filter-name>CASFilter</filter-name>
	<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
	<init-param>
		<param-name>casServerLoginUrl</param-name>
		<!-- 這裡配置cas服務的訪問地址,用於當用戶未登入被攔截後,跳往cas的登入頁面 -->
		<param-value>http://localhost:9100/cas/login</param-value>
		<!--這裡的server是服務端的IP -->
	</init-param>
	<init-param>
		<param-name>serverName</param-name>
		<!-- 這裡配置使用者當前實際要訪問的地址,因為當在cas登入成功後,需要重定向到之前的頁面,也就是被攔截的頁面 -->
		<param-value>http://localhost:8081</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>
		<!-- 這裡配置cas服務的訪問地址,用於當用戶未登入被攔截後,跳往cas的登入頁面 -->
		<param-value>http://localhost:9100/cas</param-value>
	</init-param>
	<init-param>
		<param-name>serverName</param-name>
		<!-- 這裡配置使用者當前實際要訪問的地址,因為當在cas登入成功後,需要重定向到之前的頁面,也就是被攔截的頁面 -->
		<param-value>http://localhost:8081</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>CAS Validation Filter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

在這個工程中也建立一個jsp檔案

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登入成功2</title>
</head>
<body>	
	<!-- request.getRemoteUser()為在web.xml中配置的一個過濾器,獲取遠端登入名 -->	
	<h1>2,登入成功,</h1>歡迎你,<%=request.getRemoteUser() %>	
</body>
</html>
單點登入測試

分別把工程1、工程2、cas服務都啟動 在瀏覽器輸入 localhost:8080 和 localhost:8081時,因為沒有登入,都會跳轉到cas的預設登入頁面,但是,如果在 localhost:8080 的這個頁面登入cas成功之後,頁面就會跳轉到之前寫的jsp頁面 在這裡插入圖片描述 這時,如果再通過瀏覽器輸入localhost:8081 後,也不會再到cas的登入頁面,而是到工程2的jsp頁面 在這裡插入圖片描述 如果之前通過工程2來登入cas,效果也是一樣的,這就實現了單點登入效果。

單點登出測試

cas有一個預設的退出登入的請求:http://localhost:9100/cas/logout 執行後,就可以看到退出成功的頁面,此時再去訪問localhost:8080,localhost:8081,又會跳到cas登入頁面。但是這樣退出會預設到cas的退出成功的頁面,實際應用中,我們應該指定一個退出登入後,重定向的頁面。 修改cas系統的配置檔案cas-servlet.xml 在這裡插入圖片描述 之後再訪問http://localhost:9100/cas/logout?service=http://www.baidu.com,就能在退出登入後跳轉到百度,這裡預設必須要用service引數來傳遞一個網址。 可以修改工程1的jsp檔案,加上一個a標籤

<a href="http://localhost:9100/cas/logout?service=http://www.baidu.com">退出登入</a>

當點選退出登入後,工程1就能跳轉到百度頁面。