改造CAS单点登录 --- 自定义登陆页面(客户端)
2014-02-13 14:23
603 查看
修改版本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
2.退出不能使用,修改SingleSignOutHandler去掉POST限制
3.登录成功后,ST超时失效抛出异常解决,跳转到首页重新获取ST
修改AbstractTicketValidationFilter类doFilter方法
修改Cas20ServiceTicketValidator类parseResponseFromServer方法
二、客户端demo工程
1.创建cas-client-demo工程
2.登录页面login.jsp
3.登录成功页面index.jsp
4.web.xml配置
客户端修改配置完成。
引入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单点登录 --- 自定义登陆页面(服务端)
- 让CAS支持客户端自定义登陆页面——服务器篇
- 让CAS支持客户端自定义登陆页面——客户端篇
- 让CAS支持客户端自定义登陆页面
- 让CAS支持客户端自定义登陆页面——原理篇
- 让CAS支持客户端自定义登陆页面
- CAS单点登录自定义登录页面错误提示
- spring-oauth集成cas单点登录,登陆完成进入授权页面后,按回退按钮进入404页面的问题
- moss自定义登陆页面
- 自定义Sharepoint的登陆页面
- 自定义Sharepoint的登陆页面
- spring-oauth集成cas单点登录,登陆完成进入授权页面后,按回退按钮进入404页面的问题
- 【转】goahead 的认证和自定义登陆页面的cookie使用
- OBIEE自定义登陆和注销页面
- 自定义Sharepoint的登陆页面(2)
- spring security2学习笔记二(自定义数据结构及登陆页面)
- Android登陆页面的客户端逻辑
- 黑马程序员-TCP上传图片-多线程并发上传图片-客户端并发登陆-自定义服务器
- atlas客户端页面周期事件及实践:自定义错误
- Spring Security 自定义登陆页面报HTTP Status 403 - Invalid CSRF Token 'null' was found on the request paramet