改造CAS单点登录 --- 自定义登陆页面(客户端)

来源:互联网 发布:java定义错误枚举类 编辑:程序博客网 时间:2024/04/30 05:51

修改版本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"><ahref="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>


 

客户端修改配置完成。

 

0 0