CAS4.0 自定义客服端登陆界面

关于cas基本搭建,就不再描述了,随便一搜一大堆。我这里只关注后期的修正,当有这样一个需求:
当你登录系统软件时,不希望跳转到cas默认的页面去做登录。你希望在自己的子系统的登录页面进入。
我这里用服务端是cas4.0版本,客服端是3.1.12 其实服务器的版本之间差别还是有很多的。

实现原理:
一、 逻辑
1,客户端修改CAS Authentication Filter过滤器,该过滤器会判断用户是否登录,如果没有登录则跳转到自身配置的登录界面;
2,用户输入正确的信息,登录时,会被提交到服务端的登录流程中;
3,服务端通过新增一个remoteLogin处理类,专门处理客户端自定义登录业务;
4,该remoteLogin处理类与原始的login处理极为类似,只是修改了获取用户名与密码的方式;
5,如果用户名与密码不匹配,校验失败,会通过remoteCallbackView.jsp界面将错误提示与service一并响应给客户端的登录界面,接收之后将错误提示显示到界面上;
6,如果用户名与密码匹配,校验成功,会直接重定向到客户端的service页面,这时CAS Authentication Filter过滤器与CAS Validation Filter过滤器分别校验用户是否登录与ticket票据是否正确,完成最后的校验,否则要求用户重新登录。
二、 修改点
客户端
1. 修改web.xml,修改原先的CAS Authentication Filter过滤器
2. 新增RemoteAuthenticationFilter过滤器
3. 新增login.jsp
服务端
1. 修改web.xml,给cas过滤器添加remoteLogin servlet-mapping映射
2. 新增RemoteLoginAction登录处理类与AuthenticationViaFormAction表单处理类
3. 新增remoteLogin-webflow.xml自定义登录webflow流程文件
4. 修改cas-servlet.xml配置文件,新增一些bean配置
5. 新增remoteCallbackView.jsp响应界面,校验错误时用来通知客户端登录界面
客户端篇
1.替换原来过滤器org.jasig.cas.client.authentication.AuthenticationFilter,改成自己的过滤器RemoteAuthenticationFilter.java,参照原始的页面去修改,这个过滤器可以自己随便放到哪个包中,保证web.xml能够正确引用到就行:

package com.xb.login;

import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;

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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.Assertion;


/** 
 * qzg 17.11.01
 */ 
public class RemoteAuthenticationFilter extends AbstractCasFilter  


{  
    public static final String CONST_CAS_GATEWAY = "_const_cas_gateway_";  
    /** 
     * 本地登陆页面URL. 
     */  
    private String localLoginUrl;  

    /** 
     * The URL to the CAS Server login. 
     */  
    private String casServerLoginUrl;  
    /** 
     * Whether to send the renew request or not. 
     */  
    private boolean renew = false;  
    /** 
     * Whether to send the gateway request or not. 
     */  
    private boolean gateway = false;  

    /** Instance of commons logging for logging purposes. */
    protected final Log log = LogFactory.getLog(getClass());

    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);  
        }  
        System.out.println("---------end---2---#");  
        filterChain.doFilter(request, response);  
    }  

    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 web.xml中配置:
旧的:
CAS Authentication Filter
org.jasig.cas.client.authentication.AuthenticationFilter

casServerLoginUrl
https://localhost:8443/cas/login


serverName
http://localhost:8080


renew
false


gateway
false


修改后:

     <filter>  
        <filter-name>CASFilterfilter-name>  
        <filter-class>com.xb.login.RemoteAuthenticationFilterfilter-class>  
        <init-param>  
            <param-name>localLoginUrlparam-name>  
            <param-value>http://127.0.0.1:8080/casClient/login.jspparam-value>  
        init-param>  
        <init-param>  
            <param-name>casServerLoginUrlparam-name>  
            <param-value>https://sso.castest.com:8443/cas/remoteLoginparam-value>  
        init-param>  
        <init-param>  
            <param-name>serverNameparam-name>  
            <param-value>http://127.0.0.1:8080param-value>  
        init-param>  
    filter>  

        <filter-mapping>
                <filter-name>CASFilterfilter-name>
                <url-pattern>/pages/*url-pattern>
        filter-mapping>
        <filter-mapping>
                <filter-name>CASFilterfilter-name>
                <url-pattern>*.actionurl-pattern>
        filter-mapping>

3.加上你自己定义的登录界面,就是子系统的login.jsp

    <%@ page language="java" contentType="text/html; charset=utf-8"  
        pageEncoding="utf-8"%>  
      

 <html>     
 <head>  
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
    <title>系统1客户端登录title>  

    <script type="text/javascript">  
        function getParam(name)  
        {  
            var queryString = window.location.search;  
            var param = queryString.substr(1, queryString.length - 1).split("&");  
            for (var i = 0; i < param.length; i++)  
            {  
                var keyValue = param[i].split("=");  
                if (keyValue[0] == name)  
                    return keyValue[1];  
            }  
            return null;  
        }  
        function init()  
        {  
            // 显示异常信息  
            var error = getParam("errorMessage");  
            if (error)  
            {  
                document.getElementById("errorMessage").innerHTML = decodeURIComponent(error);  
            }  

            // 注入service  
            var service = getParam("service");  
            console.log("service:"+service);
            if (service)  
                document.getElementById("service").value = decodeURIComponent(service);  
            else  
                document.getElementById("service").value = location.href;  

            var loginTicket = getParam("loginTicket");  
            console.log("loginTicket:"+loginTicket);
            if (loginTicket)  
                document.getElementById("loginTicket").value = decodeURIComponent(loginTicket);  
            else  
                document.getElementById("loginTicket").value = ''; 
         // 这个参数在4.0之前的版本没有,搞了我好久。。。。
            var flowExecutionKey = getParam("flowExecutionKey");  
            console.log("flowExecutionKey:"+flowExecutionKey);
            if (flowExecutionKey)  
                document.getElementById("execution").value = decodeURIComponent(flowExecutionKey);  
            else  
                document.getElementById("execution").value = '';



        }  
    script>  
    head>  
    <body>  
        <h1>系统1客户端登录h1>  
        <div id="errorMessage" style="color: red;">div>  
        <form id="myLoginForm" action="https://sso.castest.com:8443/cas/remoteLogin"  
            method="post">  
             <input type="hidden" name="service" value="http://127.0.0.1:8080/casClient/index.jsp">  
            <input type="hidden" name="loginUrl" value="http://127.0.0.1:8080/casClient/login.jsp">  
            <input type="hidden" name="submit" value="LOGIN" /> 
            <input type="hidden" name="msubmit" value="true" />   
            <input type="hidden" name="lt" id="loginTicket" value="" /> 
             <input type="hidden" name="execution" id="execution" value="" /> 
             <input type="hidden" name="service" id="service" value="" />
             <input type="hidden" name="_eventId" value="submit" />
            <table>  
                <tr>  
                    <td>用户名:td>  
                    <td><input type="text" name="username">td>  
                tr>  
                <tr>  
                    <td>密  码:td>  
                    <td><input type="password" name="password">td>  
                tr>  
                <tr>  
                    <td colspan="2"><input type="submit" value="登陆" />td>  
                tr>  
            table>  
        form>  

<a href="https://sso.castest.com:8443/cas/logout">注销登录a>


        <script type="text/javascript">  
            init()  
        script>  
    body>  
    html>  

客户端完成改造。
服务端篇
1.添加客户端登录Action,org.jasig.cas.web.flow.RemoteLoginAction:一样的是参照源码修改的。可以先看看源码再去修改。

package com.xb.casLogin;


import java.text.SimpleDateFormat;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.jasig.cas.authentication.principal.Service;
import org.jasig.cas.web.support.ArgumentExtractor;
import org.jasig.cas.web.support.CookieRetrievingCookieGenerator;
import org.jasig.cas.web.support.WebUtils;
import org.springframework.util.StringUtils;
import org.springframework.webflow.action.AbstractAction;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
/** 
 * 
 * org.jasig.cas.web.flow.RemoteLoginAction:
 * 远程登陆票据提供Action. 根据InitialFlowSetupAction修改. 
 * 由于InitialFlowSetupAction为final类,因此只能将代码复制过来再进行修改. 
 */  
public class RemoteLoginAction extends AbstractAction  
{  
    /** CookieGenerator for the Warnings. */  
    @NotNull  
    private CookieRetrievingCookieGenerator warnCookieGenerator;  
    /** CookieGenerator for the TicketGrantingTickets. */  
    @NotNull  
    private CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator;  
    /** Extractors for finding the service. */  
    @NotNull  
    @Size(min = 1)  
    private List argumentExtractors;  
    /** Boolean to note whether we've set the values on the generators or not. */  
    private boolean pathPopulated = false;  

    protected Event doExecute(final RequestContext context) throws Exception  
    {  
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String timetodaypi= sdf.format(new java.util.Date());
        System.out.println(timetodaypi+"----------------------------Relogin------go--------------------------------------------------");
        final HttpServletRequest request = WebUtils.getHttpServletRequest(context);
        if (!this.pathPopulated) {
            final String contextPath = context.getExternalContext().getContextPath();
            final String cookiePath = StringUtils.hasText(contextPath) ? contextPath + "/" : "/";
            logger.info("Setting path for cookies to: "
                + cookiePath);
            this.warnCookieGenerator.setCookiePath(cookiePath);
            this.ticketGrantingTicketCookieGenerator.setCookiePath(cookiePath);
            this.pathPopulated = true;
        }
        context.getFlowScope().put(
            "ticketGrantingTicketId", this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request));
        context.getFlowScope().put(
            "warnCookieValue",
            Boolean.valueOf(this.warnCookieGenerator.retrieveCookieValue(request)));

        // 存放service url  
        //context.getFlowScope().put("serviceUrl", request.getParameter("service"));  
        final Service service = WebUtils.getService(this.argumentExtractors,  
                context);  
        if (service != null && logger.isDebugEnabled())  
        {  
            logger.debug("Placing service in FlowScope: " + service.getId());  
        }  
        context.getFlowScope().put("service", service);  


        // 客户端必须传递loginUrl参数过来,否则无法确定登陆目标页面    loginUrl
        System.out.println("------loginUrl--"+request.getParameter("loginUrl"));
        if (StringUtils.hasText(request.getParameter("loginUrl")))  
        {  
            context.getFlowScope().put("remoteLoginUrl",  
                    request.getParameter("loginUrl"));  
        } else  
        {  
            request.setAttribute("remoteLoginMessage",  
                    "loginUrl parameter must be supported.");  
            return result("error");
        }  
        // 若参数包含submit则进行提交,否则进行验证   
        if (StringUtils.hasText(request.getParameter("msubmit")))  
        {  
            return result("submit");  
        } else  
        {  
            return result("checkTicketGrantingTicket");  
        } 

    }  

    public void setTicketGrantingTicketCookieGenerator(  
            final CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator)  
    {  
        this.ticketGrantingTicketCookieGenerator = ticketGrantingTicketCookieGenerator;  
    }  

    public void setWarnCookieGenerator(  
            final CookieRetrievingCookieGenerator warnCookieGenerator)  
    {  
        this.warnCookieGenerator = warnCookieGenerator;  
    }  

    public void setArgumentExtractors(  
            final List argumentExtractors)  
    {  
        this.argumentExtractors = argumentExtractors;  
    }  
}  

2 web.xml配置,

<servlet-mapping>  
     <servlet-name>casservlet-name>  
     <url-pattern>/remoteLoginurl-pattern>  
 servlet-mapping> 

3 cas-servlet.xml中最后面增加以下信息



<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
       http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd">

  <import resource="spring-configuration/propertyFileConfigurer.xml"/>

  
  <bean id="themeResolver" class="org.jasig.cas.services.web.ServiceThemeResolver"
        p:defaultThemeName="${cas.themeResolver.defaultThemeName}"
        p:argumentExtractors-ref="argumentExtractors"
        p:servicesManager-ref="servicesManager">
    <property name="mobileBrowsers">
      <util:map>
        <entry key=".*iPhone.*" value="iphone"/>
        <entry key=".*Android.*" value="iphone"/>
        <entry key=".*Safari.*Pre.*" value="iphone"/>
        <entry key=".*Nokia.*AppleWebKit.*" value="iphone"/>
      util:map>
    property>
  bean>

  
  <bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver"
        p:order="0">
    <property name="basenames">
      <util:list>
        <value>${cas.viewResolver.basename}value>
        <value>protocol_viewsvalue>
      util:list>
    property>
  bean>

  
  <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" p:defaultLocale="en" />

  <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>

  <bean id="urlBasedViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"
        p:viewClass="org.springframework.web.servlet.view.InternalResourceView"
        p:prefix="/WEB-INF/view/jsp/"
        p:suffix=".jsp"
        p:order="1"/>

  <bean id="errorHandlerResolver" class="org.jasig.cas.web.FlowExecutionExceptionResolver"/>

  <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

  <bean
      id="handlerMappingC"
      class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"
      p:alwaysUseFullPath="true">
    <property name="mappings">
      <util:properties>
        <prop key="/serviceValidate">serviceValidateControllerprop>
        <prop key="/proxyValidate">proxyValidateControllerprop>

        <prop key="/p3/serviceValidate">v3ServiceValidateControllerprop>
        <prop key="/p3/proxyValidate">v3ProxyValidateControllerprop>

        <prop key="/validate">legacyValidateControllerprop>
        <prop key="/proxy">proxyControllerprop>
        <prop key="/authorizationFailure.html">passThroughControllerprop>
        <prop key="/status">healthCheckControllerprop>
        <prop key="/statistics">statisticsControllerprop>
      util:properties>
    property>
    
  bean>

  <bean id="passThroughController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>

  
  <bean id="loginFlowHandlerMapping" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"
        p:flowRegistry-ref="loginFlowRegistry" p:order="2">
    <property name="interceptors">
      <ref local="localeChangeInterceptor" />
    property>
  bean>

  <bean id="loginHandlerAdapter" class="org.jasig.cas.web.flow.SelectiveFlowHandlerAdapter"
        p:supportedFlowId="login" p:flowExecutor-ref="loginFlowExecutor" p:flowUrlHandler-ref="loginFlowUrlHandler" />

  <bean id="loginFlowUrlHandler" class="org.jasig.cas.web.flow.CasDefaultFlowUrlHandler" />

  <webflow:flow-executor id="loginFlowExecutor" flow-registry="loginFlowRegistry">
    <webflow:flow-execution-attributes>
      <webflow:always-redirect-on-pause value="false" />
      <webflow:redirect-in-same-state value="false" />
    webflow:flow-execution-attributes>
    <webflow:flow-execution-listeners>
      <webflow:listener ref="terminateWebSessionListener" />
    webflow:flow-execution-listeners>
  webflow:flow-executor>

  <webflow:flow-registry id="loginFlowRegistry" flow-builder-services="builder">
    <webflow:flow-location path="/WEB-INF/login-webflow.xml" id="login" />
  webflow:flow-registry>

  
  <bean id="logoutFlowHandlerMapping" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"
        p:flowRegistry-ref="logoutFlowRegistry" p:order="3">
    <property name="interceptors">
      <ref local="localeChangeInterceptor" />
    property>
  bean>

  <bean id="logoutHandlerAdapter" class="org.jasig.cas.web.flow.SelectiveFlowHandlerAdapter"
        p:supportedFlowId="logout" p:flowExecutor-ref="logoutFlowExecutor" p:flowUrlHandler-ref="logoutFlowUrlHandler" />

  <bean id="logoutFlowUrlHandler" class="org.jasig.cas.web.flow.CasDefaultFlowUrlHandler"
        p:flowExecutionKeyParameter="RelayState" />

  <webflow:flow-executor id="logoutFlowExecutor" flow-registry="logoutFlowRegistry">
    <webflow:flow-execution-attributes>
      <webflow:always-redirect-on-pause value="false" />
      <webflow:redirect-in-same-state value="false" />
    webflow:flow-execution-attributes>
    <webflow:flow-execution-listeners>
      <webflow:listener ref="terminateWebSessionListener" />
    webflow:flow-execution-listeners>
  webflow:flow-executor>

  <webflow:flow-registry id="logoutFlowRegistry" flow-builder-services="builder">
    <webflow:flow-location path="/WEB-INF/logout-webflow.xml" id="logout" />
  webflow:flow-registry>

  <webflow:flow-builder-services id="builder" view-factory-creator="viewFactoryCreator" expression-parser="expressionParser" />

  <bean id="logoutConversionService" class="org.jasig.cas.web.flow.LogoutConversionService" />

  <bean id="terminateWebSessionListener" class="org.jasig.cas.web.flow.TerminateWebSessionListener" 
  p:timeToDieInSeconds="10"/>

  <bean id="expressionParser" class="org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser"
        c:conversionService-ref="logoutConversionService">
    <constructor-arg>
        <bean class="org.springframework.expression.spel.standard.SpelExpressionParser" />
    constructor-arg>
  bean>

  <bean id="viewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
    <property name="viewResolvers">
      <util:list>
        <ref local="viewResolver"/>
      util:list>
    property>
  bean>

       
  <bean id="abstractValidateController" class="org.jasig.cas.web.ServiceValidateController" abstract="true"
        p:centralAuthenticationService-ref="centralAuthenticationService"
        p:proxyHandler-ref="proxy20Handler"
        p:argumentExtractor-ref="casArgumentExtractor"/>

  <bean id="proxyValidateController" parent="abstractValidateController"/>

  <bean id="serviceValidateController" parent="abstractValidateController"
        p:validationSpecificationClass="org.jasig.cas.validation.Cas20WithoutProxyingValidationSpecification"/>

  
  <bean id="v3AbstractValidateController" parent="abstractValidateController" abstract="true"
        p:successView="cas3ServiceSuccessView"
        p:failureView="cas3ServiceFailureView" />

  <bean id="v3ProxyValidateController" parent="v3AbstractValidateController" />

  <bean id="v3ServiceValidateController" parent="v3AbstractValidateController"
        p:validationSpecificationClass="org.jasig.cas.validation.Cas20WithoutProxyingValidationSpecification"/>

         
  <bean id="legacyValidateController" parent="abstractValidateController"
        p:proxyHandler-ref="proxy10Handler"
        p:successView="cas1ServiceSuccessView"
        p:failureView="cas1ServiceFailureView"
        p:validationSpecificationClass="org.jasig.cas.validation.Cas10ProtocolValidationSpecification"/>

  <bean id="proxyController" class="org.jasig.cas.web.ProxyController"
        p:centralAuthenticationService-ref="centralAuthenticationService"/>

  <bean id="statisticsController" class="org.jasig.cas.web.StatisticsController"
        p:casTicketSuffix="${host.name}" c:ticketRegistry-ref="ticketRegistry" />

  <bean id="logoutAction" class="org.jasig.cas.web.flow.LogoutAction"
        p:servicesManager-ref="servicesManager"
        p:followServiceRedirects="${cas.logout.followServiceRedirects:false}"/>

  <bean id="frontChannelLogoutAction" class="org.jasig.cas.web.flow.FrontChannelLogoutAction"
        c:logoutManager-ref="logoutManager"/>

  <bean id="healthCheckController" class="org.jasig.cas.web.HealthCheckController"
        p:healthCheckMonitor-ref="healthCheckMonitor"/>


  <bean id="initialFlowSetupAction" class="org.jasig.cas.web.flow.InitialFlowSetupAction"
        p:argumentExtractors-ref="argumentExtractors"
        p:warnCookieGenerator-ref="warnCookieGenerator"
        p:ticketGrantingTicketCookieGenerator-ref="ticketGrantingTicketCookieGenerator"/>

  <bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction"
        p:centralAuthenticationService-ref="centralAuthenticationService"
        p:warnCookieGenerator-ref="warnCookieGenerator"
        p:ticketRegistry-ref="ticketRegistry"/>

  <bean id="authenticationExceptionHandler" class="org.jasig.cas.web.flow.AuthenticationExceptionHandler" />

  <bean id="generateServiceTicketAction" class="org.jasig.cas.web.flow.GenerateServiceTicketAction"
        p:centralAuthenticationService-ref="centralAuthenticationService"/>

  <bean id="sendTicketGrantingTicketAction" class="org.jasig.cas.web.flow.SendTicketGrantingTicketAction"
        p:centralAuthenticationService-ref="centralAuthenticationService"
        p:ticketGrantingTicketCookieGenerator-ref="ticketGrantingTicketCookieGenerator"/>

  <bean id="gatewayServicesManagementCheck" class="org.jasig.cas.web.flow.GatewayServicesManagementCheck"
    c:servicesManager-ref="servicesManager" />

  <bean id="serviceAuthorizationCheck" class="org.jasig.cas.web.flow.ServiceAuthorizationCheck"
    c:servicesManager-ref="servicesManager" />

  <bean id="generateLoginTicketAction" class="org.jasig.cas.web.flow.GenerateLoginTicketAction"
        p:ticketIdGenerator-ref="loginTicketUniqueIdGenerator"/>

  <bean id="messageInterpolator" class="org.jasig.cas.util.SpringAwareMessageMessageInterpolator"/>

  <bean id="credentialsValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"
        p:messageInterpolator-ref="messageInterpolator"/>

  <bean id="ticketGrantingTicketCheckAction" class="org.jasig.cas.web.flow.TicketGrantingTicketCheckAction"
        c:registry-ref="ticketRegistry" />

  <bean id="terminateSessionAction" class="org.jasig.cas.web.flow.TerminateSessionAction"
        c:cas-ref="centralAuthenticationService"
        c:tgtCookieGenerator-ref="ticketGrantingTicketCookieGenerator"
        c:warnCookieGenerator-ref="warnCookieGenerator"/>





 
    <bean id="handlerMappingB"
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/remoteLogin">remoteLoginControllerprop>

            props>
        property>
        <property name="interceptors">
            <list>
                <ref bean="localeChangeInterceptor" />
            list>
        property>
    bean>
<bean id="flowUrlHandler" class="org.jasig.cas.web.flow.CasDefaultFlowUrlHandler" />
    <bean id="remoteLoginController" class="org.springframework.webflow.mvc.servlet.FlowController">
        <property name="flowExecutor" ref="remoteLoginFlowExecutor" />
        <property name="flowUrlHandler" ref="loginFlowUrlHandler" />
    bean>

    <webflow:flow-executor id="remoteLoginFlowExecutor"
        flow-registry="remoteLoginFlowRegistry">
        <webflow:flow-execution-attributes>
            <webflow:always-redirect-on-pause
                value="false" />
        webflow:flow-execution-attributes>
    webflow:flow-executor>

    <webflow:flow-registry id="remoteLoginFlowRegistry"
        flow-builder-services="builder">
        <webflow:flow-location path="/WEB-INF/remoteLogin-webflow.xml"
            id="remoteLogin" />
    webflow:flow-registry>

    <webflow:flow-builder-services id="flowBuilderServices"
        view-factory-creator="viewFactoryCreator" />

    <bean id="remoteLoginAction" class="com.xb.casLogin.RemoteLoginAction"
        p:argumentExtractors-ref="argumentExtractors"
        p:warnCookieGenerator-ref="warnCookieGenerator"
        p:ticketGrantingTicketCookieGenerator-ref="ticketGrantingTicketCookieGenerator" />




beans>

4,新建一个文件与login-webflow.xml同级,remoteLogin-webflow.xml:,这个与3.0的版本有很多差别,如果你用的还是3.0版本的。就需要注意了。


<flow xmlns="http://www.springframework.org/schema/webflow"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
    start-state="remoteLogin">

    
    <var name="credentials"
        class="org.jasig.cas.authentication.UsernamePasswordCredential" />

    
    <action-state id="remoteLogin">
        <evaluate expression="remoteLoginAction" />
        <transition on="error" to="viewServiceErrorView" />
        <transition on="submit" to="bindAndValidate" />
        <transition on="checkTicketGrantingTicket" to="ticketGrantingTicketExistsCheck" />
    action-state>




    <action-state id="ticketGrantingTicketExistsCheck">
        <evaluate expression="ticketGrantingTicketCheckAction.checkValidity(flowRequestContext)"/>
        <transition on="notExists" to="gatewayRequestCheck"/>
        <transition on="invalid" to="terminateSession"/>
        <transition on="valid" to="hasServiceCheck"/>
    action-state>

    <action-state id="terminateSession">
        <evaluate expression="terminateSessionAction.terminate(flowRequestContext)"/>
        <transition to="generateLoginTicket"/>
    action-state>
    <decision-state id="gatewayRequestCheck">
        <if test="requestParameters.gateway != '' and requestParameters.gateway != null and flowScope.service != null" 
        then="gatewayServicesManagementCheck" else="serviceAuthorizationCheck" />
    decision-state>

    <decision-state id="hasServiceCheck">
        <if test="flowScope.service != null"
        then="renewRequestCheck"
            else="viewGenericLoginSuccess" />
    decision-state>

    <decision-state id="renewRequestCheck">
        <if test="requestParameters.renew != '' and requestParameters.renew != null" 
        then="serviceAuthorizationCheck" else="generateServiceTicket" />
    decision-state>
 
    <action-state id="serviceAuthorizationCheck">
        <evaluate expression="serviceAuthorizationCheck"/>
        <transition to="generateLoginTicket"/>
    action-state> 

    <decision-state id="warn">
        <if test="flowScope.warnCookieValue" 
        then="showWarningView" else="redirect" />
    decision-state>
    
    <action-state id="generateLoginTicket">
        <evaluate expression="generateLoginTicketAction.generate(flowRequestContext)" />
        <transition on="generated" to="remoteCallbackView" />
    action-state> 

    
    
    <view-state id="remoteCallbackView" view="remoteCallbackView" model="credentials">     
       <binder>
            <binding property="username" />
            <binding property="password" />
        binder>
        <on-entry>
            <set name="viewScope.commandName" value="'credentials'" />
        on-entry>
        <transition on="submit" bind="true" validate="true" to="realSubmit">
            <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
        transition>
    view-state>
    
    <view-state id="viewLoginForm" view="casLoginView" model="credentials">
        <binder>
            <binding property="username" />
            <binding property="password" />
        binder>
        <on-entry>
            <set name="viewScope.commandName" value="'credentials'" />
        on-entry>
        <transition on="submit" bind="true" validate="true" to="realSubmit">
            <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
        transition>
    view-state>
   <action-state id="realSubmit">
    <evaluate expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credentials, messageContext)" />
    <transition on="warn" to="warn" />
    <transition on="success" to="sendTicketGrantingTicket" />
    <transition on="successWithWarnings" to="showMessages" />
    <transition on="authenticationFailure" to="handleAuthenticationFailure" />
    <transition on="error" to="generateLoginTicket" />
  action-state>



   <view-state id="showMessages" view="casLoginMessageView">
    <on-entry>
      <evaluate expression="sendTicketGrantingTicketAction" />
      <set name="requestScope.messages" value="messageContext.allMessages" />
    on-entry>
    <transition on="proceed" to="serviceCheck" />
  view-state>


    <action-state id="handleAuthenticationFailure">
    <evaluate expression="authenticationExceptionHandler.handle(currentEvent.attributes.error, messageContext)" />
    <transition on="AccountDisabledException" to="casAccountDisabledView"/>
    <transition on="AccountLockedException" to="casAccountLockedView"/>
    <transition on="CredentialExpiredException" to="casExpiredPassView"/>
    <transition on="InvalidLoginLocationException" to="casBadWorkstationView"/>
    <transition on="InvalidLoginTimeException" to="casBadHoursView"/>
    <transition on="FailedLoginException" to="generateLoginTicket"/>
    <transition on="AccountNotFoundException" to="generateLoginTicket"/>
    <transition on="UNKNOWN" to="generateLoginTicket"/>
  action-state>

    <action-state id="sendTicketGrantingTicket">
        <evaluate expression="sendTicketGrantingTicketAction" />
        <transition to="serviceCheck" />
    action-state>

    <decision-state id="serviceCheck">
        <if test="flowScope.service != null" 
            then="generateServiceTicket"
            else="viewGenericLoginSuccess" />
    decision-state>

    <action-state id="generateServiceTicket">
        <evaluate expression="generateServiceTicketAction" />
        <transition on="success" to="warn" />
        <transition on="error" to="generateLoginTicket" />
        <transition on="gateway" to="gatewayServicesManagementCheck" />
        <transition on="authenticationFailure" to="handleAuthenticationFailure" />
    action-state>

    <action-state id="gatewayServicesManagementCheck">
        <evaluate expression="gatewayServicesManagementCheck" />
        <transition on="success" to="redirect" />
    action-state>

    <action-state id="redirect">
        <evaluate
            expression="flowScope.service.getResponse(requestScope.serviceTicketId)"
            result-type="org.jasig.cas.authentication.principal.Response" 
            result="requestScope.response" />
        <transition to="postRedirectDecision" />
    action-state>
    <decision-state id="postRedirectDecision">
        <if test="requestScope.response.responseType.name() == 'POST'" 
        then="postView" else="redirectView" />
    decision-state>

    
    <end-state id="viewGenericLoginSuccess" view="casLoginGenericSuccessView" />

    <end-state id="showWarningView" view="casLoginConfirmView" />






     
  <end-state id="abstactPasswordChangeView">
    <on-entry>
      <set name="flowScope.passwordPolicyUrl" value="passwordPolicy.passwordPolicyUrl" />
    on-entry>
  end-state>
  <end-state id="casExpiredPassView" view="casExpiredPassView" parent="#abstactPasswordChangeView" />
  <end-state id="casMustChangePassView" view="casMustChangePassView" parent="#abstactPasswordChangeView" />
  <end-state id="casAccountDisabledView" view="casAccountDisabledView" />
  <end-state id="casAccountLockedView" view="casAccountLockedView" />
  <end-state id="casBadHoursView" view="casBadHoursView" />
  <end-state id="casBadWorkstationView" view="casBadWorkstationView" />

    <end-state id="postView" view="postResponseView">
        <on-entry>
            <set name="requestScope.parameters" value="requestScope.response.attributes" />
            <set name="requestScope.originalUrl" value="flowScope.service.id" />
        on-entry>
    end-state>
    
    <end-state id="redirectView" view="externalRedirect:#{requestScope.response.url}" />

    <end-state id="viewServiceErrorView" view="viewServiceErrorView" />
    <end-state id="viewServiceSsoErrorView" view="viewServiceSsoErrorView" />

    <global-transitions>
        <transition to="viewServiceErrorView"
            on-exception="org.springframework.webflow.execution.repository.NoSuchFlowExecutionException" />
        <transition to="viewServiceSsoErrorView"
            on-exception="org.jasig.cas.services.UnauthorizedSsoServiceException" />
        <transition to="viewServiceErrorView"
            on-exception="org.jasig.cas.services.UnauthorizedServiceException" />
    global-transitions>
flow>

5,回调页面jsp:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>  
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
<script type="text/javascript">  
    var remoteUrl = "${remoteLoginUrl}?validated=true";  
    //登陆回调页面。    
    var re1 = '${loginTicket}';
    var re2 = '${flowExecutionKey}';
    console.log("-loginTicket--"+re1);
    console.log("-execution--"+re2);
   // 构造错误消息,从webflow scope中取出  
    var errorMessage = '${remoteLoginMessage}';  
    /*  
     errorMessage = "&errorMessage=" + encodeURIComponent(''); 
     */  
    // 如果存在错误消息则追加到 url中  
    if(null != errorMessage && errorMessage.length > 0)  
    {  
        errorMessage = "&errorMessage=" + encodeURIComponent(errorMessage);  
    }  
    console.log("客户端remoteUrl:---"+remoteUrl + errorMessage );
    // 构造service  
    var service = "";
    var loginTicket = "";
    <c:if test="${service != null && service != ''}">  
     service = "&service=" + encodeURIComponent("${service}");  
    </c:if>  
    <c:if test="${loginTicket != null && loginTicket != ''}">  
     loginTicket = "&loginTicket=" + "${loginTicket}";  
    </c:if> 
    console.log("客户端service:"+ service);
    var flowExecutionKey ="&flowExecutionKey=" + re2; 

    // 跳转回去(客户端)  
  window.location.href = remoteUrl + errorMessage + service+loginTicket+flowExecutionKey;  



  </script>

6.在default_views.properties中新增以下两句:
remoteCallbackView.(class)=org.springframework.web.servlet.view.JstlView
remoteCallbackView.url=/WEB-INF/view/jsp/default/ui/remoteCallbackView.jsp

完成,希望你也能一次成功。
当访问子系统的资源时:
127.0.0.1:8080/casClient/pages/index.jsp
会被拦截然后调往服务端的remoteLogin流程。服务器处理完后,地址链接就会跳转到:
127.0.0.1:8080/casClient/login.jsp?validated=true&service=http%3A%2F%2F127.0.0.1%3A8080%2FcasClient%2Fpages%2Findex.jsp&loginTicket=LT-2-gqkSPrIxkevb5TyqU2QprMQauC92OE-cas01.example.org&flowExecutionKey=e1s1
此时我们看到2 个关键的参数已经有值 loginTicket和 flowExecutionKey。
登录界面如下:
CAS4.0 自定义客服端登陆界面_第1张图片

下面是我自己项目的连接地址,有需要可以去下载。
http://download.csdn.net/download/qinzuoguo/10133874

你可能感兴趣的:(java)