CAS-5.3單點登錄/退出客戶端搭建(Springboot)

使用Springboot搭建cas客戶端,主要是配置四個過濾器和一個監聽器。

單點登錄

創建過濾器類

用于過濾不需要登錄的用戶,需要實現UrlPatternMatcherStrategy 接口,在matches 函數里添加不需要用戶登錄的鏈接。

package com.zhang.springbootcasclient1.auth;

import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;

import java.util.regex.Pattern;

/**
 * @Auther: zhang
 * @Date: 2018/8/30 09:46
 * @Description:過濾掉不需要授權登錄的頁面
 */
public class SimpleUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy{
    private Pattern pattern;
    /**
     * description:判斷是否匹配這個字符串
     * @param: [url]用戶請求的連接
     * @return: true:不需要攔截
     *          false:必須要登錄
     */
    @Override
    public boolean matches(String url) {
        //使用正則表達式來匹配需要忽略的連接
        return this.pattern.matcher(url).find();
    }

    /**
     * description:正則表達式的規則,該規則在配置AuthenticationFilter的ignorePattern中設置
     * @param: [pattern]
     * @return: void
     */
    @Override
    public void setPattern(String pattern) {
        this.pattern = Pattern.compile(pattern);
    }
}

創建首頁控制器

package com.zhang.springbootcasclient1.controller;

import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.Map;

/**
 * @Auther: zhangll
 * @Date: 2018/8/30 10:11
 * @Description:
 */
@Controller
public class IndexController {
    @RequestMapping(value={"/", "/index"})
    public String index(HttpServletRequest request) {

        //獲取cas給我們傳遞回來的對象,這個對象在Session中
        //session的 key是 CONST_CAS_ASSERTION
        Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);

        Principal principal  = assertion.getPrincipal();

        String loginName =principal.getName();
        System.out.printf("登錄用戶名:%s\r\n",loginName);

        System.out.printf("ValidFromDate:%s\r\n",assertion.getValidFromDate());
        System.out.printf("ValidUntilDate:%s\r\n",assertion.getValidUntilDate());
        System.out.printf("AuthenticationDate:%s\r\n",assertion.getAuthenticationDate());

        //獲取自定義返回值的數據
        if (principal instanceof AttributePrincipal) {
            //cas傳遞過來的數據
            Map<String,Object> result =( (AttributePrincipal)principal).getAttributes();
            for(Map.Entry<String, Object> entry :result.entrySet()) {
                String key = entry.getKey();
                Object val = entry.getValue();
                System.out.printf("%s:%s\r\n",key,val);
            }
        }

        return "index";
    }
}

首頁代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>當前所在子系統:測試系統1</h1>
<h2><a >系統1</a></h2>
<h2><a >系統2</a></h2>
<b>Authenticated User Id:</b> <a href="logout.jsp" title="Click here to log out" th:text="${#request.remoteUser}"/>
<br/>
<a th:href="${#request.contextPath}+'/logoutDefault'" title="Click here to log out">退出系統(默認退出頁面)</a>
<a th:href="${#request.contextPath}+'/logoutCustom'" title="Click here to log out">退出系統(定制退出頁面)</a>
</body>
</html>

用戶退出控制器

package com.zhang.springbootcasclient1.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;

/**
 * @Auther: zhangll
 * @Date: 2018/8/30 11:35
 * @Description:
 */
@Controller
public class LogoutController {
    @RequestMapping("/logoutDefault")
    public String logout1(HttpSession session) {
        session.invalidate();

        // 直接退出,走默認退出方式
        return "redirect:https://casserver.com:8443/logout";
    }

    @RequestMapping("/logoutCustom")
    public String logout2(HttpSession session) {
        session.invalidate();
        // 退出登錄后,跳轉到退出成功的頁面,不走默認頁面
        return "redirect:https://casserver.com:8443/logout?service=http://springbootcasclient.com:8001/logout/success";
    }

    @RequestMapping("/logout/success")
    @ResponseBody
    public String logout2() {
        return "系統1注銷成功";
    }
}

配置過濾器到springboot

package com.zhang.springbootcasclient1;

import org.jasig.cas.client.authentication.AuthenticationFilter;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;

import java.util.EventListener;
import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
public class SpringbootCasClient1Application {
    private static final String CAS_SERVER_URL_PREFIX = "https://casserver.com:8443/";
    private static final String CAS_SERVER_URL_LOGIN = "https://casserver.com:8443/login";

    //本機的名稱
    private static final String SERVER_NAME = "http://springbootcasclient.com:8001/";

    /**
     * description: 登錄過濾器
     * @param: []
     * @return: org.springframework.boot.web.servlet.FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean filterSingleRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new SingleSignOutFilter());
        // 設定匹配的路徑
        registration.addUrlPatterns("/*");
        Map<String,String> initParameters = new HashMap<String, String>();
        initParameters.put("casServerUrlPrefix", CAS_SERVER_URL_PREFIX);
        registration.setInitParameters(initParameters);
        // 設定加載的順序
        registration.setOrder(1);
        return registration;
    }


    /**
     * description:過濾驗證器
     *     * @param: []
     * @return: org.springframework.boot.web.servlet.FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean filterValidationRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new Cas30ProxyReceivingTicketValidationFilter());
        // 設定匹配的路徑
        registration.addUrlPatterns("/*");
        Map<String,String>  initParameters = new HashMap<String, String>();
        initParameters.put("casServerUrlPrefix", CAS_SERVER_URL_PREFIX);
        initParameters.put("serverName", SERVER_NAME);
        initParameters.put("useSession", "true");
        registration.setInitParameters(initParameters);
        // 設定加載的順序
        registration.setOrder(1);
        return registration;
    }


    /**
     * description:授權過濾器
     * @param: []
     * @return: org.springframework.boot.web.servlet.FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean filterAuthenticationRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new AuthenticationFilter());
        // 設定匹配的路徑
        registration.addUrlPatterns("/*");
        Map<String,String>  initParameters = new HashMap<String, String>();
        initParameters.put("casServerLoginUrl", CAS_SERVER_URL_LOGIN);
        initParameters.put("serverName", SERVER_NAME);
        //忽略/logout的路徑
        initParameters.put("ignorePattern", "/logout/*");
        initParameters.put("ignoreUrlPatternType", "com.zhang.springbootcasclient1.auth.SimpleUrlPatternMatcherStrategy");

        registration.setInitParameters(initParameters);
        // 設定加載的順序
        registration.setOrder(1);
        return registration;
    }

    /**
     * wraper過濾器
     * @return
     */
    @Bean
    public FilterRegistrationBean filterWrapperRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new HttpServletRequestWrapperFilter());
        // 設定匹配的路徑
        registration.addUrlPatterns("/*");
        // 設定加載的順序
        registration.setOrder(1);
        return registration;
    }

    /**
     * 添加監聽器
     * @return
     */
    @Bean
    public ServletListenerRegistrationBean<EventListener> singleSignOutListenerRegistration(){
        ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<EventListener>();
        registrationBean.setListener(new SingleSignOutHttpSessionListener());
        registrationBean.setOrder(1);
        return registrationBean;
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringbootCasClient1Application.class, args);
    }
}

application.properties

logging.file=logs/config/springboot-cas-client1.log
info.name=springboot-cas-client1

server.port=8001

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zhang</groupId>
    <artifactId>springboot-cas-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot-cas-client</name>
    <description>Demo project for Spring Boot CAS Client</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <java.cas.client.version>3.5.0</java.cas.client.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--cas客戶端 -->
        <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-core</artifactId>
            <version>${java.cas.client.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

登錄測試

按照同樣的方法實現客戶端系統2。
啟動cas服務器端和兩個客戶端。輸入http://springbootcasclient.com:8001/,則跳轉到登錄界面

client1_login.png

輸入用戶名和密碼(casuser/Mellon),則進入客戶端系統1的index頁面。
client1-index.png

輸入http://springbootcasclient.com:8002/,直接跳轉到客戶端系統2的index頁面,不需要再重新登錄。
client2-index.png

單點退出

單點退出,需要下面三個步驟:1、添加過濾器類,過濾掉不需要登錄的url;2、添加退出跳轉的控制器;3、修改服務端application.properties ,加cas.logout.followServiceRedirects=true,讓客戶端可以自己制定退出的路徑,否則會走默認退出路徑。

添加過濾器類

過濾器類需要實現UrlPatternMatcherStrategy接口,然后配置到springboot中,請參考單點登錄創建過濾器類配置過濾器到springboot

添加退出控制器

退出的方式有兩種,一種是走默認的路徑,另一種是走自定義的返回路徑。請參考單點登錄用戶退出控制器

修改服務端application.properties

cas.logout.followServiceRedirects=true

將上面的內容添加到applicaiton.properties, 這樣就可以允許客戶端定制自己的退出路徑了。

注意問題

http協議配置:cas 5.3.x默認客戶端不支持http協議, 如果不進行配置,則會出現“未認證授權的服務”錯誤。


unauthorized-service-error.png

要配置兼容http協議,需要在HTTPSandIMAPS-10000001.json文件中添加http。


HTTPSandIMAPS-10000001.png

同時需要在application.properties中添加
cas.serviceRegistry.initFromJson=true
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容