cas5.3.9實(shí)現(xiàn)多客戶端單點(diǎn)登錄單點(diǎn)登出案例

經(jīng)過一個(gè)星期的業(yè)余時(shí)間研究侥祭,終于學(xué)會(huì)了用cas5.3.9這個(gè)版本做單點(diǎn)登錄單點(diǎn)登出功能秩霍,還是比較簡(jiǎn)單方便的宵呛,在此記錄一下单匣。

cas5.3.9是基于springboot開發(fā),只支持1.8jdk以上和tomcat8以上宝穗,這里用1.8jdk和tomcat8.5跑cas服務(wù)端户秤,用1.8jdk和tomcat7跑普通ssm web客戶端

操作步驟大體可分為以下幾步:
1.去cas官網(wǎng)github地址下載cas5.3.9的cas-overlay-template-5.3.zip
2.根據(jù)解壓的這個(gè)文件overlay一個(gè)cas服務(wù)端,基于maven構(gòu)建方式
3.建立maven cas項(xiàng)目,把生成的cas web服務(wù)端文件復(fù)制到這個(gè)項(xiàng)目中逮矛,更改一些必要配置鸡号,兼容http訪問和數(shù)據(jù)庫讀取user表方式驗(yàn)證,跑起cas服務(wù)端
4.ssm web客戶端引入cas必要的jar包依賴须鼎,解決jar包沖突問題鲸伴,配置web.xml實(shí)現(xiàn)單點(diǎn)登入登出
5.寫測(cè)試頁面測(cè)試登入登出功能

一、去cas官網(wǎng)github地址下載cas5.3.9的cas-overlay-template-5.3.zip
地址:https://github.com/apereo/cas-overlay-template/tree/5.3
二晋控、根據(jù)解壓的這個(gè)文件overlay一個(gè)cas服務(wù)端汞窗,基于maven構(gòu)建方式
下載解壓之后,按照里面的readme.md指導(dǎo)文件上所說的方式編譯一個(gè)cas項(xiàng)目出來
./build.sh help可以看到里面的各種命令
./build.sh clean 清除target
./build.sh package 打包
也可以直接在解壓的文件里直接運(yùn)行:
mvn clean
mvn install
以上都是linux的構(gòu)建方式 如果是windows赡译,則要在cmd里打開這個(gè)解壓的文件夾運(yùn)行build.cmd clean
build.cmd package
命令就可以打包啦

有可能會(huì)打包失敗仲吏,因?yàn)閲?guó)內(nèi)被墻的原因,下載速度奇慢蝌焚,所以如果打包失敗了裹唆,八成原因是maven庫里的
.m2/repository/org/apereo/cas/cas-server-webapp-tomcat/5.3.9/cas-server-webapp-tomcat-5.3.9.war這個(gè)文件下載不成功導(dǎo)致,這個(gè)還比較大只洒,有一百多M
所以最簡(jiǎn)單的方法就是去一個(gè)maven項(xiàng)目里许帐,在pom.xml里加入這個(gè)文件的依賴地址,點(diǎn)擊保存就會(huì)自動(dòng)下載到庫里啦毕谴,如果maven庫用的是國(guó)內(nèi)比如阿里云的私服就很快下載完啦成畦。
依賴地址:

        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-webapp-tomcat</artifactId>
            <version>5.3.9</version>
            <type>war</type>
        </dependency>

下載完這個(gè)war包之后距芬,再重新進(jìn)行上面的打包操作就很快打包成功啦,打包成功后會(huì)看到一個(gè)target文件夾羡鸥,里面的cas.war和解壓的cas就是項(xiàng)目代碼啦是可以直接在tomcat8.5下運(yùn)行的

三蔑穴、建立maven cas項(xiàng)目,把生成的cas web服務(wù)端文件復(fù)制到這個(gè)項(xiàng)目中忠寻,更改一些必要配置惧浴,兼容http訪問和數(shù)據(jù)庫讀取user表方式驗(yàn)證,跑起cas服務(wù)端
用eclipse New一個(gè)maven web項(xiàng)目奕剃,把解壓出來的cas文件夾下的文件都放在webapp下面


深度截圖_選擇區(qū)域_20190803172010.png

生成的結(jié)構(gòu)如圖:


深度截圖_選擇區(qū)域_20190803172157.png

把WEB-INF/classes/application.properties復(fù)制到resources文件夾下
把WEB-INF/classes/services文件夾復(fù)制到resources文件夾下
如圖:


深度截圖_選擇區(qū)域_20190803172625.png

更改HTTPSandIMAPS-10000001.json 加入|http


深度截圖_選擇區(qū)域_20190803172854.png

更改application.properties 加入以下配置

cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true
# Json services \u914D\u7F6E\u4F4D\u7F6E\u8BBE\u5B9A
#cas.serviceRegistry.json.location=classpath:/services

至此加入http協(xié)議支持就完成啦

接下來加入jar包支持oracle數(shù)據(jù)庫衷旅,pom.xml里加入以下依賴

        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-support-jdbc-drivers</artifactId>
            <version>5.3.9</version>
        </dependency>
        
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-support-jdbc</artifactId>
            <version>5.3.9</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/com.oracle.jdbc/ojdbc6 -->
        <dependency>
            <groupId>com.oracle.jdbc</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.1.0.6.0</version>
        </dependency>

oracle驅(qū)動(dòng)是試了很久才知道必須用ojdbc6的,用其他版本的oracle或許會(huì)jar包沖突纵朋,項(xiàng)目要求jdk1.8的柿顶,ojdbc6是支持1.8的,ojdbc14就不行操软,上面的兩個(gè)cas-server jdbc jar包也必須是5.3.9的 用其他版本也會(huì)沖突 如果是mysql數(shù)據(jù)庫則可以用mysql的數(shù)據(jù)庫驅(qū)動(dòng)jar包
application.properties里加入數(shù)據(jù)庫配置

cas.authn.jdbc.query[0].url=jdbc\:oracle\:thin\:@127.0.0.1\:1521\:xe
cas.authn.jdbc.query[0].user=zhaohy
cas.authn.jdbc.query[0].password=oracle
cas.authn.jdbc.query[0].sql=select * from da_user where user_name=?
cas.authn.jdbc.query[0].fieldPassword=password
cas.authn.jdbc.query[0].driverClass=oracle.jdbc.OracleDriver

至此cas就可以讀取數(shù)據(jù)庫里的user表來完成賬戶用戶名和密碼驗(yàn)證啦嘁锯,對(duì)了,cas默認(rèn)的賬戶配置不要忘了注釋掉:

#cas.authn.accept.users=casuser::Mellons

以上聂薪,cas的服務(wù)端配置就完成了家乘,把cas項(xiàng)目部署到tomcat8.5中可以運(yùn)行成功,數(shù)據(jù)庫里面未加密的用戶名密碼可以通過驗(yàn)證藏澳。

項(xiàng)目跑起來后訪問本地cas地址:

http://127.0.0.1:8082/cas/login

可以跳轉(zhuǎn)到登錄頁面 輸入數(shù)據(jù)庫中的用戶名和密碼即可登錄成功

補(bǔ)充:

配置cas自帶md5加密方式

只需要在application.properties增加如下代碼:

#配置md5加密
cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5

數(shù)據(jù)庫存儲(chǔ)md5加密之后的密碼仁锯,再重新啟動(dòng)cas,輸入明文密碼也可以登錄

配置自定義加密類

自定義加密類必須要實(shí)現(xiàn)org.springframework.security.crypto.password.PasswordEncoder這個(gè)接口
創(chuàng)建自定義加密類MD5Util

package com.zhaohy.app.util;

import java.security.MessageDigest;

import org.springframework.security.crypto.password.PasswordEncoder;


/**
 * MD5加密
 * @author Administrator
 *
 */
public class MD5Util implements PasswordEncoder {
    /**
     * Title: MD5加密 生成32位md5碼
     * Description: TestDemo
     * @author lu
     * @date 2016年6月23日 下午2:36:07
     * @param inStr
     * @return 返回32位md5碼
     * @throws Exception
     */
    public static String md5Encode(String inStr) throws Exception {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
            return "";
        }
        byte[] byteArray = inStr.getBytes("UTF-8");
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }
    /**
     * Title: MD5加密
     * Description: TestDemo
     * @author lu
     * @date 2016年6月23日 下午2:43:31
     * @param inStr
     * @return
     */
    public static String string2MD5(String inStr) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
            return "";
        }
        char[] charArray = inStr.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16)
                hexValue.append("0");
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();

    }

    /**
     * Title: 加密解密算法 執(zhí)行一次加密翔悠,兩次解密
     * Description: TestDemo
     * @author lu
     * @date 2016年6月23日 下午2:37:29
     * @param inStr
     * @return
     */
    public static String convertMD5(String inStr) {

        char[] a = inStr.toCharArray();
        for (int i = 0; i < a.length; i++) {
            a[i] = (char) (a[i] ^ 't');
        }
        String s = new String(a);
        return s;

    }
    public static String md5Decode(String str) {
        return convertMD5(convertMD5(str));
    }

    public static void main(String[] args) {//e10adc3949ba59abbe56e057f20f883e
        String s = new String("123456");
        System.out.println(md5Decode("a6aeb3ffa55fc7d664406af9c3bd0f1b"));
        System.out.println("原始:" + s);
        System.out.println("MD5后:" + string2MD5(s));
        System.out.println("加密的:" + convertMD5(s));
        System.out.println("解密的:" + convertMD5(convertMD5(s)));
    }
    
    /**
     * 對(duì)輸入的密碼加密過程
     */
    @Override
    public String encode(CharSequence inputPwd) {
        System.out.println("inputPwd===" + inputPwd);
        System.out.println("string2MD5==" + string2MD5(inputPwd.toString()));
        return string2MD5(inputPwd.toString());
    }
    
    /**
     * 密碼校驗(yàn)過程
     */
    @Override
    public boolean matches(CharSequence inputPwd, String dbPwd) {
        // 判斷密碼是否存在
        if (inputPwd == null) {
            return false;
        }
        System.out.println("inputPwd==" + inputPwd + "  " + "dbPwd==" + dbPwd);
        if(dbPwd.contentEquals(this.encode(inputPwd))){
            return true;
        }
        return false;
    }
}

其中的encode和matches方法是實(shí)現(xiàn)PasswordEncoder接口的方法业崖,一個(gè)做加密處理,一個(gè)做校驗(yàn)處理蓄愁。
application.properties增加如下代碼:

#自定義密碼加密方式
cas.authn.jdbc.query[0].passwordEncoder.type=com.zhaohy.app.util.MD5Util
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8

重啟cas之后也能登錄成功双炕。

四、ssm web客戶端引入cas必要的jar包依賴撮抓,解決jar包沖突問題雄家,配置web.xml實(shí)現(xiàn)單點(diǎn)登入登出

建立兩個(gè)ssm客戶端項(xiàng)目,分別為ssmTest05,ssmTest05-1
在客戶端項(xiàng)目中pom.xml引入jar包:

        <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-core</artifactId>
            <version>3.5.1</version>
            <exclusions>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.0.pr1</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.4</version>
        </dependency>
        
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

上面的cas-client-core.3.5.1.jar依賴jackson-databind 2.8.8的版本胀滚,但是這個(gè)版本跟我用的spring 5.1.8.RELEASE 版本沖突趟济,所以剔除了這個(gè)jackson,用了2.10.0.pr1版本的jackson-databind

web.xml配置:

<!-- ======================== 單點(diǎn)登錄開始 ======================== -->
    <!-- 用于單點(diǎn)退出咽笼,該過濾器用于實(shí)現(xiàn)單點(diǎn)登出功能顷编,可選配置-->
    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!-- 該過濾器用于實(shí)現(xiàn)單點(diǎn)登出功能,可選配置剑刑。 -->
    <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:8082/cas</param-value>
       </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 該過濾器負(fù)責(zé)用戶的認(rèn)證工作媳纬,必須啟用它 -->
    <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://127.0.0.1:8082/cas/login</param-value>
        </init-param>
        <!--
            指定客戶端的域名和端口双肤,是指客戶端應(yīng)用所在機(jī)器而不是 CAS Server
        -->
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://127.0.0.1:8081</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CASFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 該過濾器負(fù)責(zé)對(duì)Ticket的校驗(yàn)工作,必須啟用它 -->
    <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://127.0.0.1:8082/cas</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://127.0.0.1:8081</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CAS Validation Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--
        該過濾器負(fù)責(zé)實(shí)現(xiàn)HttpServletRequest請(qǐng)求的包裹钮惠,
        比如允許開發(fā)者通過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>

    <!--
        該過濾器使得開發(fā)者可以通過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>
    
        
        <!-- ======================== 單點(diǎn)登錄結(jié)束 ======================== -->

        <!-- session超時(shí)定義,單位為分鐘 -->
        <session-config>
                <session-timeout>2</session-timeout>
        </session-config>

兩個(gè)ssm客戶端項(xiàng)目都是這樣配置,至此客戶端就配置完了

cas服務(wù)端application.properties文件里加入單點(diǎn)登出設(shè)置:

#配置單點(diǎn)登出
#配置允許登出后跳轉(zhuǎn)到指定頁面
cas.logout.followServiceRedirects=true
#跳轉(zhuǎn)到指定頁面需要的參數(shù)名為 service
cas.logout.redirectParameter=service
#登出后需要跳轉(zhuǎn)到的地址,如果配置該參數(shù),service將無效预明。
#cas.logout.redirectUrl=https://www.taobao.com
#在退出時(shí)是否需要 確認(rèn)退出提示   true彈出確認(rèn)提示框  false直接退出
cas.logout.confirmLogout=false
#是否移除子系統(tǒng)的票據(jù)
cas.logout.removeDescendantTickets=true
#禁用單點(diǎn)登出,默認(rèn)是false不禁止
#cas.slo.disabled=true
#默認(rèn)異步通知客戶端,清除session
cas.slo.asynchronous=true

至此缩赛,整個(gè)項(xiàng)目的配置都配置好了

五、寫測(cè)試頁面測(cè)試登入登出功能
在ssmTest05客戶端里webapp下建立index.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<script type="text/javascript">
    function backToLogin(){
        window.location="/ssmTest05/user/logout.do";
    }
</script>
<body>
<h2>Hello SpringMVC!</h2><br/>
<button id="button" onclick="backToLogin()">退出</button>
</body>
</html>

在controller里寫一個(gè)/user/logout.do接口

@RequestMapping("/user/logout")
  public void logout(HttpServletResponse response) {
      try {
        response.sendRedirect("http://127.0.0.1:8082/cas/logout?service=http://127.0.0.1:8081/ssmTest05/logout.jsp");
    } catch (IOException e) {
        e.printStackTrace();
    }
  }

在webapp下再寫一個(gè)logout.jsp撰糠,退出后重定向到項(xiàng)目會(huì)被cas攔截進(jìn)入登錄頁面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<% 
 response.sendRedirect("http://localhost:8081/ssmTest05");  //重定向
%>

</body>
</html>

在ssmTest05-1中webapp下寫一個(gè)index.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<script type="text/javascript">
    function backToLogin(){
        window.location="/ssmTest05/user/logout.do";
    }
</script>
<body>
<h2>Hello SpringMVC-222!</h2><br/>
<button id="button" onclick="backToLogin()">退出</button>
</body>
</html>

運(yùn)行cas和兩個(gè)客戶端項(xiàng)目
訪問

http://127.0.0.1:8081/ssmTest05

會(huì)被cas攔截至登錄頁面 輸入數(shù)據(jù)庫中的用戶名和密碼后成功進(jìn)入項(xiàng)目
這時(shí)訪問

http://127.0.0.1:8081/ssmTest05-1

也可以成功進(jìn)入第二個(gè)項(xiàng)目
隨便在兩個(gè)項(xiàng)目中點(diǎn)擊哪個(gè)退出按鈕酥馍,會(huì)跳轉(zhuǎn)到cas登錄頁面,在不登錄的情況下訪問哪個(gè)項(xiàng)目都會(huì)被攔截阅酪,至此單點(diǎn)登錄和登出就實(shí)現(xiàn)成功啦旨袒!

在cas客戶端里面如何拿到用戶的登錄信息呢

cas客戶端提供了org.jasig.cas.client.util.AbstractCasFilter這個(gè)類
可以在客戶端代碼中加入如下判斷來判斷用戶有沒有登錄以及拿到用戶名

      if(null == request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION)) {
            System.out.println("用戶未登錄!");
        } else {
            Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);  
            AttributePrincipal principal = assertion.getPrincipal();  
            String username = principal.getName(); 
            System.out.println("userName=op==" + username);
        }

自定義login頁面

官方參考文檔:
https://apereo.github.io/cas/5.3.x/installation/Configuration-Properties.html#themes
https://apereo.github.io/cas/5.3.x/installation/User-Interface-Customization-Themes.html

主題意味著風(fēng)格不一樣,目的就是不同的接入端,顯示不同的登錄頁面术辐,就像阿里旗下的各種登錄,支付寶登錄,淘寶砚尽,天貓,用的可能就是同一個(gè)sso,但是各自的登錄主題不一樣术吗。
簡(jiǎn)略看完后尉辑,會(huì)有以下的規(guī)范:
● 靜態(tài)資源(js,css)存放目錄為src/main/resources/static
● html資源存(thymeleaf)放目錄為src/main/resources/templates
● 主題配置文件存放在src/main/resources并且命名為[theme_name].properties
● 主題頁面html存放目錄為src/main/resources/templates/

自定義login頁面cas5也支持同時(shí)定制多種主題,可以為不同客戶端靈活使用较屿,如果不設(shè)置主題配置隧魄,cas就使用默認(rèn)主題。
可以定制動(dòng)態(tài)主題和靜態(tài)主題隘蝎,時(shí)間有限购啄,只研究了靜態(tài)主題,這里只介紹一下靜態(tài)主題的配置方法嘱么。

在客戶端注冊(cè)的json文件中添加theme屬性

如圖狮含,在src/main/resources/services/文件夾下之前已經(jīng)添加了兩個(gè)json文件,
在json文件種添加theme屬性


深度截圖_選擇區(qū)域_20190820225531.png

如:我們?cè)贖TTPSandIMAPS-10000001.json里修改

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://127.0.0.1:8081/ssmTest05-1/.*",
  "name" : "HTTPS and IMAPS",
  "id" : 10000003,
  "description" : "This service definition authorizes all application urls that support HTTPS and IMAPS protocols.",
  "evaluationOrder" : 10001,
  "theme" : "app2"
}

其中的theme就是指定自定義的主題 曼振,這里指定app2主題几迄,serviceId是對(duì)客戶端的請(qǐng)求使用該主題,可以看到這個(gè)主題對(duì)ssmTest05-1這個(gè)項(xiàng)目的請(qǐng)求使用
在app2.json里修改:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://127.0.0.1:8081/ssmTest05/.*",
  "name" : "HTTPS and IMAPS",
  "id" : 10000001,
  "description" : "This service definition authorizes all application urls that support HTTPS and IMAPS protocols.",
  "evaluationOrder" : 10000,
  "theme" : "app1"
}

這個(gè)主題對(duì)ssmTest05這個(gè)項(xiàng)目的請(qǐng)求使用

在src/main/resources下創(chuàng)建app1.properties 和 app2.properties

根據(jù)官網(wǎng)文檔,需要在src/main/resources文件夾的根目錄下創(chuàng)建 與 json文件中theme屬性值 對(duì)應(yīng)的properties
所以要在src/main/resources新建app1.properties 和 app2.properties
app1.properties:

#cas css
cas.standard.css.file=/css/cas.css
#my css
cas.myself.css=/themes/app1/css/cas.css
cas.javascript.file=/themes/app1/js/jquery-3.4.1/jquery-3.4.1.min.js
cas.page.title=app1Theme

app2.properties:

#cas css
cas.standard.css.file=/css/cas.css
#my css
cas.myself.css=/themes/app2/css/cas.css
cas.javascript.file=/themes/app1/js/jquery-3.4.1/jquery-3.4.1.min.js
cas.page.title=app2Theme

在app1.properties 和 app2.properties 中的屬性值都是隨便起,只要在html中指明引用的key就可以了,例如:properties中指明css和js文件地址,然后在html中用下面的方式使用冰评。

<link rel="stylesheet" th:href="@{${#themes.code('cas.myself.css')}}"/>
<script th:src="@{${#themes.code('cas.javascript.file')}}"></script>

注意:上面配置文件中有cas.standard.css.file屬性,這個(gè)屬性默認(rèn)就是指向/css/cas.css也就是cas默認(rèn)的css文件,這個(gè)我們要指明,否則你只是自定義了登錄頁面,其他頁面的樣式將丟失映胁。我們?cè)谧远x的登錄頁面使用自己的css文件,不跟cas的默認(rèn)css混淆。

創(chuàng)建cas.css文件

app1對(duì)應(yīng)的cas.css:

h2 {
    color: red;
}

app2對(duì)應(yīng)的cas.css

h2 {
    color: blue;
}

在application.properties中添加以下屬性甲雅,配置默認(rèn)主題

# 默認(rèn)主題
cas.theme.defaultThemeName=app1

配置不同客戶端的登錄頁面

兩個(gè)客戶端的頁面都是一樣的解孙,給一個(gè)頁面坑填,其他復(fù)制就可以了
app1下的 casLoginView.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html  xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title th:text="${#themes.code('cas.page.title')}"></title>
    <link rel="stylesheet" th:href="@{${#themes.code('cas.myself.css')}}"/>
    <script th:src="@{${#themes.code('cas.javascript.file')}}"></script>
</head>

<body>
<h2 th:text="${#themes.code('cas.page.title')}"></h2>
<div>
    <form method="post" th:object="${credential}">
        <div th:if="${#fields.hasErrors('*')}">
            <span th:each="err : ${#fields.errors('*')}" th:utext="${err}" style="color: red" />
        </div>
        <h4 th:utext="#{screen.welcome.instructions}"></h4>
        <section class="row">
            <label for="username" th:utext="#{screen.welcome.label.netid}" />
            <div th:unless="${openIdLocalId}">
                <input class="required" id="username" size="25" tabindex="1" type="text"
                       th:disabled="${guaEnabled}"
                       th:field="*{username}"
                       th:accesskey="#{screen.welcome.label.netid.accesskey}"
                       autocomplete="off"
                       th:value="admin" />
            </div>
        </section>
        <section class="row">
            <label for="password" th:utext="#{screen.welcome.label.password}"/>
            <div>
                <input class="required" type="password" id="password" size="25" tabindex="2"
                       th:accesskey="#{screen.welcome.label.password.accesskey}"
                       th:field="*{password}"
                       autocomplete="off"
                       th:value="123456" />
            </div>
        </section>
        <section>
            <input type="hidden" name="execution" th:value="${flowExecutionKey}" />
            <input type="hidden" name="_eventId" value="submit" />
            <input type="hidden" name="geolocation" />
            <input class="btn btn-submit btn-block" name="submit" accesskey="l" th:value="#{screen.welcome.button.login}" tabindex="6" type="submit" />
        </section>
    </form>
</div>
</body>
</html>

搭建完成后目錄如下:


深度截圖_選擇區(qū)域_20190820231222.png

測(cè)試

一、先直接登錄cas服務(wù),默認(rèn)使用的是app1的主題
二弛姜、訪問http://127.0.0.1:8081/ssmTest05 顯示app1的主題脐瑰。

深度截圖_選擇區(qū)域_20190820231732.png

三、訪問http://127.0.0.1:8081/ssmTest05-1 顯示app2的主題廷臼。

深度截圖_選擇區(qū)域_20190820231821.png

至此demo已寫完 cas就可以用啦
項(xiàng)目demo代碼已上傳github:
https://github.com/haiyong6/haiyongsRepository/tree/master/code/casDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末苍在,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子中剩,更是在濱河造成了極大的恐慌忌穿,老刑警劉巖抒寂,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件结啼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡屈芜,警方通過查閱死者的電腦和手機(jī)郊愧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來井佑,“玉大人属铁,你說我怎么就攤上這事」蹋” “怎么了焦蘑?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)盒发。 經(jīng)常有香客問我例嘱,道長(zhǎng),這世上最難降的妖魔是什么宁舰? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任拼卵,我火速辦了婚禮,結(jié)果婚禮上蛮艰,老公的妹妹穿的比我還像新娘腋腮。我一直安慰自己,他們只是感情好壤蚜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布即寡。 她就那樣靜靜地躺著,像睡著了一般袜刷。 火紅的嫁衣襯著肌膚如雪聪富。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天水泉,我揣著相機(jī)與錄音善涨,去河邊找鬼窒盐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛钢拧,可吹牛的內(nèi)容都是我干的蟹漓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼源内,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼葡粒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起膜钓,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤嗽交,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后颂斜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夫壁,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年沃疮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盒让。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡司蔬,死狀恐怖邑茄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情俊啼,我是刑警寧澤肺缕,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站授帕,受9級(jí)特大地震影響同木,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜豪墅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一泉手、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧偶器,春花似錦斩萌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至霎苗,卻和暖如春姆吭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唁盏。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工内狸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留检眯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓昆淡,卻偏偏與公主長(zhǎng)得像锰瘸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昂灵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容