改造CAS單點登入 --- 自定義登陸頁面(客戶端)
修改版本cas-client-3.2.1和cas-server-3.5.2,功能使用maven構建
引入cas的相關工程:cas-client-core、cas-server-core、cas-server-webapp
通過自定義認證過濾器,新增登入頁面路徑處理。廢話不多說了,直接上程式碼。
一、修改cas-client-core工程
1.自定義認證過濾器RemoteAuthenticationFilter
package org.jasig.cas.client.authentication;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
/**
* 遠端認證過濾器.
* 由於AuthenticationFilter的doFilter方法被宣告為final,
* 只好重新實現一個認證過濾器,支援localLoginUrl設定.
*
*/
public class RemoteAuthenticationFilter extends AbstractCasFilter {
public static final String CONST_CAS_GATEWAY = "_const_cas_gateway_";
/**
* The URL to the CAS Server login.
*/
private String casServerLoginUrl;
/**
* 本地登陸頁面URL.
*/
private String localLoginUrl;
/**
* Whether to send the renew request or not.
*/
private boolean renew = false;
/**
* Whether to send the gateway request or not.
*/
private boolean gateway = false;
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
super.initInternal(filterConfig);
setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, "casServerLoginUrl", null));
log.trace("Loaded CasServerLoginUrl parameter: " + this.casServerLoginUrl);
setLocalLoginUrl(getPropertyFromInitParams(filterConfig, "localLoginUrl", null));
log.trace("Loaded LocalLoginUrl parameter: " + this.localLoginUrl);
setRenew(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "renew", "false")));
log.trace("Loaded renew parameter: " + this.renew);
setGateway(Boolean.parseBoolean(getPropertyFromInitParams(filterConfig, "gateway", "false")));
log.trace("Loaded gateway parameter: " + this.gateway);
}
public void init() {
super.init();
CommonUtils.assertNotNull(this.localLoginUrl, "localLoginUrl cannot be null.");
CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
}
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final HttpSession session = request.getSession(false);
final String ticket = request.getParameter(getArtifactParameterName());
final Assertion assertion = session != null ? (Assertion) session
.getAttribute(CONST_CAS_ASSERTION) : null;
final boolean wasGatewayed = session != null
&& session.getAttribute(CONST_CAS_GATEWAY) != null;
// 如果訪問路徑為localLoginUrl且帶有validated引數則跳過
URL url = new URL(localLoginUrl);
final boolean isValidatedLocalLoginUrl = request.getRequestURI().endsWith(url.getPath()) &&
CommonUtils.isNotBlank(request.getParameter("validated"));
if (!isValidatedLocalLoginUrl && CommonUtils.isBlank(ticket) && assertion == null && !wasGatewayed) {
log.debug("no ticket and no assertion found");
if (this.gateway) {
log.debug("setting gateway attribute in session");
request.getSession(true).setAttribute(CONST_CAS_GATEWAY, "yes");
}
final String serviceUrl = constructServiceUrl(request, response);
if (log.isDebugEnabled()) {
log.debug("Constructed service url: " + serviceUrl);
}
String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), serviceUrl, this.renew, this.gateway);
// 加入localLoginUrl
urlToRedirectTo += (urlToRedirectTo.contains("?") ? "&" : "?") + "loginUrl=" + URLEncoder.encode(localLoginUrl, "utf-8");
if (log.isDebugEnabled()) {
log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
response.sendRedirect(urlToRedirectTo);
return;
}
if (session != null) {
log.debug("removing gateway attribute from session");
session.setAttribute(CONST_CAS_GATEWAY, null);
}
try {
filterChain.doFilter(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
public final void setRenew(final boolean renew) {
this.renew = renew;
}
public final void setGateway(final boolean gateway) {
this.gateway = gateway;
}
public final void setCasServerLoginUrl(final String casServerLoginUrl) {
this.casServerLoginUrl = casServerLoginUrl;
}
public final void setLocalLoginUrl(String localLoginUrl) {
this.localLoginUrl = localLoginUrl;
}
}
2.退出不能使用,修改SingleSignOutHandler去掉POST限制
public boolean isLogoutRequest(final HttpServletRequest request) {
return !isMultipartRequest(request) &&
CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName));
}
3.登入成功後,ST超時失效丟擲異常解決,跳轉到首頁重新獲取ST
org.jasig.cas.client.validation.TicketValidationException:
票根'ST-1-U6pC9f9319mNNP0XqWjX-slimsmart.cn'不符合目標服務
at org.jasig.cas.client.validation.Cas20ServiceTicketValidator.parseResponseFromServer(Cas20ServiceTicketValidator.java:85)
at org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:217)
at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:169)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.jasig.cas.client.authentication.RemoteAuthenticationFilter.doFilter(RemoteAuthenticationFilter.java:114)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:
修改AbstractTicketValidationFilter類doFilter方法
} catch (final TicketValidationException e) {
if(e.getMessage().equalsIgnoreCase("TicketValidation-slimsmart")){
response.sendRedirect(request.getRequestURL().toString());
return;
}
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
log.warn(e, e);
onFailedValidation(request, response);
if (this.exceptionOnValidationFailure) {
throw new ServletException(e);
}
return;
}
修改Cas20ServiceTicketValidator類parseResponseFromServer方法
final String error = XmlUtils.getTextForElement(response,
"authenticationFailure");
if (CommonUtils.isNotBlank(error)) {
throw new TicketValidationException("TicketValidation-slimsmart");
}
二、客戶端demo工程
1.建立cas-client-demo工程
<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>cn.slimsmart.sso.demo</groupId>
<artifactId>sso-demo</artifactId>
<version>0.0.1</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
</project>
2.登入頁面login.jsp
<%@ page language="java" pageEncoding="UTF-8"
contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>登入</title>
</head>
<body>
<form id="myLoginForm" action="https://sso.slimsmart.cn:8443/cas/remoteLogin" method="POST">
<input type="hidden" name="service" value="http://www.slimsmart.cn:8888/demo" />
<input type="hidden" name="loginUrl" value="http://www.slimsmart.cn:8888/demo/login.jsp" />
<input type="hidden" name="submit" value="true" />
<table>
<tr>
<td>使用者名稱:</td>
<td><input type="text" value="" name="username"></td>
</tr>
<tr>
<td>密碼:</td>
<td><input type="text" value="" name="password"></td>
</tr>
<tr>
<td>驗證碼:</td>
<td><input type="text" value="" name="authcode"><img src="https://sso.slimsmart.cn:8443/cas/captcha.jpg" alt="" /></td>
</tr>
<tr>
<td align="right" colspan="2"><input type="submit" /></td>
</tr>
</table>
</form>
</body>
</html>
3.登入成功頁面index.jsp
<%@ page language="java" pageEncoding="UTF-8"
contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>登入成功</title>
</head>
<body>
<div class="welcome">
您好:<%=request.getRemoteUser()%></div>
<div id="logout">
<a
href="https://sso.slimsmart.cn:8443/cas/remoteLogout?service=http://www.slimsmart.cn:8888/demo">單點登出</a>
</div>
</body>
</html>
4.web.xml配置
<!-- 用於單點退出,該過濾器用於實現單點登出功能,可選配置 -->
<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.RemoteAuthenticationFilter</filter-class>
<init-param>
<param-name>localLoginUrl</param-name>
<param-value>http://www.slimsmart.cn:8888/demo/login.jsp</param-value>
</init-param>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://sso.slimsmart.cn:8443/cas/remoteLogin</param-value>
<!--這裡的server是服務端的IP -->
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://www.slimsmart.cn:8888</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>
<param-value>https://sso.slimsmart.cn:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://www.slimsmart.cn:8888</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>
相關文章
- CAS SSO單點登入客戶端環境搭建客戶端
- 3.CAS SSO單點登入客戶端環境搭建客戶端
- CAS SSO單點登入客戶端環境搭建之框架深度分析客戶端框架
- 關於CAS SSO單點登入客戶端環境搭建原始碼分析客戶端原始碼
- 自定義登入和登出頁面
- 3.CAS SSO單點登入客戶端環境搭建&原始碼獲取客戶端原始碼
- Dcat-admin 自定義登入頁面
- 單點登陸原理及程式碼(CAS)
- CAS SSO單點登入客戶端環境搭建之多租戶saas企業開發架構客戶端架構
- CAS單點登入-簡介
- CAS單點登入-https配置HTTP
- CAS SSO單點登入客戶端環境搭建之Spring Cloud + Spring Boot 企業架構客戶端CloudSpring Boot架構
- Spring Cloud + Spring Boot 企業架構之CAS SSO單點登入客戶端環境搭建CloudSpring Boot架構客戶端
- CAS單點登入-基礎搭建
- CAS SSO單點登入服務端環境搭建服務端
- IdentityServer4網頁(單點)登陸入門IDEServer網頁
- apereo cas單點登陸返回多個屬性
- CAS SSO單點登入客戶端環境搭建解析之Spring Cloud + Spring Boot企業架構客戶端CloudSpring Boot架構
- Spring Cloud + Spring Boot + Mybatis 企業架構之CAS SSO單點登入客戶端環境搭建CloudSpring BootMyBatis架構客戶端
- CAS單點登入(SSO)實戰(一)
- CAS SSO單點登入框架學習框架
- 跨域分散式系統單點登入的實現(CAS單點登入)跨域分散式
- 單點登陸
- 客戶端登陸logout操作,事務回滾客戶端Go
- 登陸頁面測試
- SpringCloud大型企業分散式微服務雲架構原始碼+CAS SSO單點登入客戶端環境搭建SpringGCCloud分散式微服務架構原始碼客戶端
- 簡單的網頁登入頁面網頁
- 直播平臺搭建,實現自定義設定登入頁面
- CAS SSO單點登入客戶端環境搭建之java版spring cloud 分散式微服務企業快速架構客戶端JavaSpringCloud分散式微服務架構
- Java版分散式微服務雲開發架構 Spring Cloud之CAS SSO單點登入客戶端環境搭建Java分散式微服務架構SpringCloud客戶端
- 登入頁面
- vnc登入工具,好用的vnc登入工具,具體登入vnc客戶端使用教程VNC客戶端
- CAS SSO單點登入服務端環境搭建之框架深度分析服務端框架
- 2.CAS SSO單點登入服務端環境搭建原始碼服務端原始碼
- 14、sso單點登陸
- CAS SSO單點登入客戶端環境搭建之Java版微服務雲開發架構 Spring Cloud+Spring Boot客戶端Java微服務架構CloudSpring Boot
- 【開發必備】單點登入,清除了cookie,頁面還保持登入狀態?Cookie
- CAS實現單點登入SSO執行原理探究
- tkinter做一個簡單的登陸頁面(十六)