CAS 5.2.x 單點登陸 - 搭建服務端和客戶端

1、簡介

單點登陸(Single Sign On),簡稱爲 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。

CAS 是一個開源的企業級單點登陸系統,目前最新版本爲 5.2.x
CAS 包含兩個部分:CAS Server 和 CAS Client,它們之間獨立部署。CAS 客戶端攔截未認證的用戶請求,並重定向至 CAS 服務端,由 CAS 服務端對用戶身份進行統一認證。html

2、搭建服務端

對於本地搭建 CAS 服務端,官方提供了基於 Maven 和 Gradle 的 Overlay 構建方式,本文用的是 CAS Maven WAR Overlayjava

2.1 什麼是 WAR Overlay?

Overlay 技術能夠把多個項目 war 合併成爲一個項目,若是項目存在同名文件,那麼主項目中的文件將覆蓋掉其餘項目的同名文件。

使用 Overlay 無需對 CAS 源碼進行編譯,也避免了對 CAS 源碼進行侵入性改造。node

2.2 環境清單

  • JDK 1.8
  • Tomcat 8.0+
  • IntelliJ IDEA 2017.2

2.3 Overlay 構建

下載 CAS Maven WAR Overlay,修改 pom.xml ,設置 CAS 版本爲 5.2.2。建議去除掉 pom.xml 文件中的 wrapper-maven-plugin 和無用的 profile 配置。git

<properties>
    <cas.version>5.2.2</cas.version>
</properties>

首次導入 IDEA,能夠看到後臺正在下載官方 cas.war。github

CAS Maven Overlay

工程 overlays 目錄下的文件是由 maven 編譯後才產生的,能夠在 pom.xml 中配置官方 cas.war 中的文件的那些文件能夠排除,不要在 overlays 中生成:web

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <warName>cas</warName>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <recompressZippedFiles>false</recompressZippedFiles>
        <archive>
            <compress>false</compress>
            <manifestFile>${manifestFileToUse}</manifestFile>
        </archive>
        <overlays>
            <overlay>
                <groupId>org.apereo.cas</groupId>
                <artifactId>cas-server-webapp${app.server}</artifactId>
                <!--原有的服務再也不初始化進去-->
                <excludes>
                    <exclude>WEB-INF/classes/services/*</exclude>
                    <exclude>WEB-INF/classes/application.*</exclude>
                </excludes>
            </overlay>
        </overlays>
    </configuration>
</plugin>

打開 Project Structure,能夠觀察到該工程具備兩個 Web Root,可是 src/main/webapp 目錄並不存在,須要進行手動建立。apache

Project Structure

拷貝 overlays 目錄下的 application.properties 配置文件至 resources 目錄,用於覆蓋 CAS WAR 中的同名文件。最終工程目錄結構以下:json

Project Structure

爲工程配置 tomcat 8.0 並啓動,注意 CAS 5.2.x 不支持低於 tomcat 8.0 的版本。
看到控制檯打印 READY 代表啓動成功。tomcat

CAS Server Ready

訪問 http://localhost:8080/cas/login 進入登陸界面。java-web

登陸界面

其中Non-secure Connection提示須要配置 SSL,Static Authentication提示須要對用戶配置進行修改,能夠修改成 JDBC、REST 等方式。目前用戶配置寫死在 application.properties 配置文件中,用戶名爲 casuser,密碼爲 Mellon。

##
# CAS Authentication Credentials
#
cas.authn.accept.users=casuser::Mellon

2.4 Services配置

客戶端接入 CAS 首先須要在服務端進行註冊,不然客戶端訪問將提示「未認證受權的服務」警告:

未認證受權的服務

在 resources 文件夾下建立 services 文件夾進行服務定義,該目錄中可包含多個 JSON 文件,其命名必須知足如下規則:

JSON fileName = serviceName + "-" + serviceNumericId + ".json"

建立 services/Localhost-10000003.json 文件,表示容許全部以 http://localhost 開頭的認證請求:

{
  "@class": "org.apereo.cas.services.RegexRegisteredService",
  "serviceId": "^(http)://localhost.*",
  "name": "本地服務",
  "id": 10000003,
  "description": "這是一個本地容許的服務,經過localhost訪問都容許經過",
  "evaluationOrder": 1
}

對其中屬性的說明以下,更多詳細內容見官方文檔-Service-Management

  • @class:必須爲org.apereo.cas.services.RegisteredService的實現類
  • serviceId:對服務進行描述的表達式,可用於匹配一個或多個 URL 地址
  • name: 服務名稱
  • id:全局惟一標誌
  • evaluationOrder:定義多個服務的執行順序

最後,根據官方文檔-service-registry,還需修改 application.properties 文件告知 CAS 服務端從本地加載服務定義文件:

#開啓識別json文件,默認false
cas.serviceRegistry.initFromJson=true
#自動掃描服務配置,默認開啓
#cas.serviceRegistry.watcherEnabled=true
#120秒掃描一遍
#cas.serviceRegistry.repeatInterval=120000
#延遲15秒開啓
#cas.serviceRegistry.startDelay=15000
#資源加載路徑
#cas.serviceRegistry.config.location=classpath:/services

啓動時打印如下日誌,說明服務註冊成功。

2018-03-18 23:36:08,660 INFO [org.apereo.cas.services.AbstractServicesManager] - <Loaded [0] service(s) from [InMemoryServiceRegistry].>
2018-03-18 23:36:08,876 INFO [org.apereo.cas.config.CasServiceRegistryInitializationConfiguration] - <Attempting to initialize the service registry [InMemoryServiceRegistry] from service definition resources found at [class path resource [services]]>
2018-03-18 23:36:08,877 WARN [org.apereo.cas.services.ServiceRegistryInitializer] - <Service registry [InMemoryServiceRegistry] will be auto-initialized from JSON service definitions. This behavior is only useful for testing purposes and MAY NOT be appropriate for production. Consider turning off this behavior via the setting [cas.serviceRegistry.initFromJson=false] and explicitly register definitions in the services registry.>
2018-03-18 23:36:09,283 INFO [org.apereo.cas.services.AbstractServicesManager] - <Loaded [3] service(s) from [InMemoryServiceRegistry].>

3、搭建客戶端

官方文檔中提供了 CAS Java 客戶端樣例,即 cas-sample-java-webapp
修改 pom.xml,修改 tomcat7-maven-plugin 設置訪問地址爲http://localhost:8181/node1

<!--  tomcat7 plugin -->
<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <port>8181</port>
        <uriEncoding>UTF-8</uriEncoding>
        <server>tomcat7</server>
        <path>/node1</path>
    </configuration>
</plugin>

CAS Client 經過攔截器將未認證的請求重定向到 CAS Server,這裏對 cas-sample-java-webapp 的 web.xml 文件進行修改,將服務端、客戶端地址替換爲實際測試的地址:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<!--
   <context-param>
       <param-name>renew</param-name>
       <param-value>true</param-value>
   </context-param>
-->
    <!--單點登出過濾器-->
    <filter>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <param-value>http://localhost:8080/cas</param-value>
        </init-param>
    </filter>

    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!--用來跳轉登陸-->
    <filter>
        <filter-name>CAS Authentication Filter</filter-name>
        <!--<filter-class>org.jasig.cas.client.authentication.Saml11AuthenticationFilter</filter-class>-->
        <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>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <!--這是客戶端的部署地址,認證時會帶着這個地址,認證成功後會跳轉到這個地址-->
            <param-value>http://localhost:8181/node1</param-value>
        </init-param>
    </filter>

    <!--Ticket校驗過濾器-->
    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <!--<filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class>-->
        <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</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:8181/node1</param-value>
        </init-param>
        <init-param>
            <param-name>redirectAfterValidation</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>useSession</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>authn_method</param-name>
            <param-value>mfa-duo</param-value>
        </init-param>
    </filter>

    <!-- 該過濾器負責實現HttpServletRequest請求的包裹,好比容許開發者經過HttpServletRequest的getRemoteUser()方法得到SSO登陸用戶的登陸名,可選配置-->
    <filter>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
    </filter>

    <!-- 該過濾器使得開發者能夠經過org.jasig.cas.client.util.AssertionHolder來獲取用戶的登陸名。 好比AssertionHolder.getAssertion().getPrincipal().getName()-->
    <!--<filter>
        <filter-name>CASAssertion Thread LocalFilter</filter-name>
        <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CASAssertion Thread LocalFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>-->

    <filter-mapping>
        <filter-name>CAS Single Sign Out 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 Authentication 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>

    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
</web-app>

此時訪問
http://localhost:8181/node1
會跳轉至
http://localhost:8080/cas/login?service=http%3A%2F%2Flocalhost%3A8181%2Fnode1%2F
輸入用戶信息,登陸成功,返回
http://localhost:8181/node1/;jsessionid=6628138DCAAA5BA3481CD4C9238FEBFF

CAS Client

利用相同的方法配置第二個客戶端,訪問地址爲http://localhost:8282/node2,可知在 node1 登陸成功的狀況下,無需再次輸入用戶密碼便可訪問 node2 後臺頁面。

至此,開發環境搭建完畢。因爲客戶端只是對 web.xml 中的過濾器進行配置,能夠很方便地集成到各個業務系統中。


轉載請註明出處。

相關文章
相關標籤/搜索