使用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