cas源码改造-改造登录页面

实现原理:客户端提供一个登录界面,其中action为服务端登录地址,通过改写服务端的登录代码,生成ticket票据,写cookie,重定向到客户端的service地址(如果验证失败同样,并有错误码返回),过滤器判断是否带有ticket,验证通过获取远程用户名。

1、使用源码构建自己工程
版本:
cas-server  3.5.2  (https://github.com/apereo/cas/releases/tag/v3.5.2)
cas-client  3.4.1  (https://github.com/apereo/java-cas-client/releases)
cas-demo 为测试工程

cas源码改造-改造登录页面_第1张图片

其它的工程都是插件,可以不用(groupId,artifactId,version也可以自己定义)
改造登录页面分为服务器端和客户端,下面分别说明
2、服务器端改造
1)重载AuthenticationViaFormAction 的submit和validatorCode方法
submit 方法去掉了credentials 参数,该参数自己创建。用户名和密码从request 中获得。并且自定义errorCode 作为返回客户端的提示code。
this.centralAuthenticationService.createTicketGrantingTicket(credentials) 方法中实现了验证用户名和密码的方法。

public final String submit(final RequestContext context, final MessageContext messageContext) throws Exception {

        final String ticketGrantingTicketId = WebUtils.getTicketGrantingTicketId(context);
        final Service service = WebUtils.getService(context);
        final HttpServletRequest request = WebUtils.getHttpServletRequest(context);

        //用户名和密码从rquest 中获得
        String username = request.getParameter("username");
        if(!StringUtils.hasText(username)){
            context.getFlowScope().put("errorCode", "required.username");//设置errorCode ,在跳转页面返回给demo 页面提示错误信息
            return "error";
        }
        String password = request.getParameter("password");
        if(!StringUtils.hasText(password)){
            context.getFlowScope().put("errorCode", "required.password");
            return "error";
        }

        //用户名和密码从rquest 中获得,自己构建对象
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials();
        credentials.setUsername(username);
        credentials.setPassword(password);

        if (StringUtils.hasText(context.getRequestParameters().get("renew")) && ticketGrantingTicketId != null && service != null) {
            try {
                final String serviceTicketId = this.centralAuthenticationService.grantServiceTicket(ticketGrantingTicketId, service, credentials);
                WebUtils.putServiceTicketInRequestScope(context, serviceTicketId);
                putWarnCookieIfRequestParameterPresent(context);
                return "warn";
            } catch (final TicketException e) {
                if (e.getCause() != null && AuthenticationException.class.isAssignableFrom(e.getCause().getClass())) {
                    //populateErrorsInstance(e, messageContext);
                    context.getFlowScope().put("errorCode", e.getCode());
                    return "error";
                }
                this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);
                if (logger.isDebugEnabled()) {
                    logger.debug("Attempted to generate a ServiceTicket using renew=true with different credentials", e);
                }
            }
        }
        try {
            //createTicketGrantingTicket 方法验证用户名和密码(实现类SimpleTestUsernamePasswordAuthenticationHandler)
            WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials));
            putWarnCookieIfRequestParameterPresent(context);
            return "success";
        } catch (final TicketException e) {
            //populateErrorsInstance(e, messageContext);
            context.getFlowScope().put("errorCode", e.getCode());
            return "error";
        }
    }
validatorCode 方法,参考:http://blog.csdn.net/convict_eva/article/details/52848475。只是参数不同

    public final String validatorCode(final RequestContext context, final MessageContext messageContext) throws Exception {

        final HttpServletRequest request = WebUtils.getHttpServletRequest(context);

        HttpSession session = request.getSession();
        String authcode = (String)session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
        session.removeAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);

        String submitAuthcode =request.getParameter("authcode");
        if(!StringUtils.hasText(submitAuthcode)){
            context.getFlowScope().put("errorCode", NullAuthcodeAuthenticationException.CODE);
            return "error";
        }
        if(submitAuthcode.equals(authcode)){
            context.getFlowScope().remove("errorCode");
            return "success";
        }
        context.getFlowScope().put("errorCode", BadAuthcodeAuthenticationException.CODE);
        return "error";
    }


2)自定义登录RemoteLoginAction(远程登陆票据提供Action,根据InitialFlowSetupAction修改,相关的webflow 根据login-webflow.xml 修改)

package org.jasig.cas.web.flow;

import org.hibernate.validator.constraints.NotEmpty;
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;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.util.List;

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. */
    @NotEmpty
    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 {
        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)));

        final Service service = WebUtils.getService(this.argumentExtractors,context);

        if (service != null && logger.isDebugEnabled()) {
            logger.debug("Placing service in FlowScope: " + service.getId());
        }
        context.getFlowScope().put("contextPath", request.getContextPath());
        context.getFlowScope().put("service", service);


        // 客户端必须传递loginUrl参数过来,否则无法确定登陆目标页面。作用:登录失败后重定向页面
        if (StringUtils.hasText(request.getParameter("loginUrl"))) {
            context.getFlowScope().put("remoteLoginUrl", request.getParameter("loginUrl"));
        } else {
            request.setAttribute("remoteLoginMessage", "loginUrl parameter must be supported.");
            return error();
        }

        // 若参数包含submit则进行提交,否则进行验证票据
        if (StringUtils.hasText(request.getParameter("submit"))) {
            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;
    }
}


3)自定义退出RemoteLogoutAction。销毁票据,删除cookie后,跳转到指定的cas-server-web 的页面中,在此页面中再一次跳转到指定的页面。
package org.jasig.cas.web.flow;

import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotEmpty;
import org.jasig.cas.CentralAuthenticationService;
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;

public class RemoteLogoutAction extends AbstractAction {
    @NotNull
    private CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator;
    @NotNull
    private CookieRetrievingCookieGenerator warnCookieGenerator;
    @NotNull
    private CentralAuthenticationService centralAuthenticationService;
    @NotEmpty
    private List argumentExtractors;
    private boolean pathPopulated = false;

    @Override
    protected Event doExecute(final RequestContext context) throws Exception {
        final HttpServletRequest request = WebUtils
                .getHttpServletRequest(context);
        final HttpServletResponse response = WebUtils
                .getHttpServletResponse(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)));
        final Service service = WebUtils.getService(this.argumentExtractors,context);
        if (service != null && logger.isDebugEnabled()) {
            logger.debug("Placing service in FlowScope: " + service.getId());
        }

        //回跳url 放入FlowScope 中
        context.getFlowScope().put("service", service);
        context.getFlowScope().put("remoteLoginUrl",request.getParameter("service"));
        final String ticketGrantingTicketId = this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request);

        if (ticketGrantingTicketId != null) {
            this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);//销毁TGT
            this.ticketGrantingTicketCookieGenerator.removeCookie(response);//删除cookie
            this.warnCookieGenerator.removeCookie(response);
        }
        return result("success");
    }

    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;
    }

    public void setCentralAuthenticationService(
            final CentralAuthenticationService centralAuthenticationService) {
        this.centralAuthenticationService = centralAuthenticationService;
    }
}


修改cas-server-webapp 工程 

4)web.xml,添加请求的servlet

  
  
    cas
    /remoteLogin
  

  
    cas
    /remoteLogout
  
5)在cas-servlet.xml增加请求流程


    
        
            
                remoteLoginController
                remoteLogoutController
            
        
        
            
                
            
        
    

    
        
        
    

    
        
            
        
    

    
        
    

    

    

    
        
        
    
    
        
            
        
    
    
        
    

    

    


6)增加远程登录流程控制remoteLogin-webflow.xml



       
       
              
              
              
              
       

       
       

       
              
              
              
       

       
              
              
              
       

       
              
       

       
              
       
       
              
       

       
              
              
              
              
       

       
              
       

       
              
              
              
              
       

       
              
              
       

       
              
       

       

       
              
              
       

       
              
       
       
              
                     
                     
              
       
       

       
       

       
              
              
              
       


7)增加远程退出流程控制remoteLogout-webflow.xml




       
       
              
              
       
       
       
              
              
              
       


8)配置remoteCallbackView显示节点,修改src/default_views.properties文件,增加remoteCallbackView配置

### 配置自定义远程登录失败回调页面
remoteCallbackView.(class)=org.springframework.web.servlet.view.JstlView
remoteCallbackView.url=/WEB-INF/view/jsp/default/ui/remoteCallbackView.jsp


9)创建/WEB-INF/view/jsp/default/ui/remoteCallbackView.jsp文件(即上面的jsp页面)

<%@ page language="java" contentType="text/html; charset=utf-8"
         pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>



    
    

${remoteLoginMessage}


改造客户端:


1)自定义认证过滤器 RemoteAuthenticationFilter
主要改造为:
添加登录页面url属性loginUrl,验证失败时可跳转到此url
拦截验证要过滤掉此url
页面跳转url修改

package org.jasig.cas.client.authentication;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.configuration.ConfigurationKey;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.*;
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;
import java.util.HashMap;
import java.util.Map;


public class RemoteAuthenticationFilter extends AbstractCasFilter {
    /**
     * The URL to the CAS Server login.
     */
    private String casServerLoginUrl;

    /**
     * Whether to send the renew request or not.
     */
    private boolean renew = false;


    /**
     * 本地登陆页面URL,登录失败重定向的页面。
     */
    private String localLoginUrl;


    /**
     * Whether to send the gateway request or not.
     */
    private boolean gateway = false;

    private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();

    private AuthenticationRedirectStrategy authenticationRedirectStrategy = new DefaultAuthenticationRedirectStrategy();

    private UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass = null;

    private static final Map> PATTERN_MATCHER_TYPES =
            new HashMap>();

    static {
        PATTERN_MATCHER_TYPES.put("CONTAINS", ContainsPatternUrlPatternMatcherStrategy.class);
        PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);
        PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class);
    }

    public RemoteAuthenticationFilter() {
        this(Protocol.CAS2);
    }

    protected RemoteAuthenticationFilter(final Protocol protocol) {
        super(protocol);
    }
    
    protected void initInternal(final FilterConfig filterConfig) throws ServletException {
        if (!isIgnoreInitConfiguration()) {
            super.initInternal(filterConfig);
            setCasServerLoginUrl(getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL));
            setLocalLoginUrl(getString(new ConfigurationKey("localLoginUrl", null)));//加载配置
            setRenew(getBoolean(ConfigurationKeys.RENEW));
            setGateway(getBoolean(ConfigurationKeys.GATEWAY));
                       
            final String ignorePattern = getString(ConfigurationKeys.IGNORE_PATTERN);//忽略拦截url配置
            final String ignoreUrlPatternType = getString(ConfigurationKeys.IGNORE_URL_PATTERN_TYPE);
            
            if (ignorePattern != null) {
                final Class ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
                if (ignoreUrlMatcherClass != null) {
                    this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlMatcherClass.getName());
                } else {
                    try {
                        logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);
                        this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlPatternType);
                    } catch (final IllegalArgumentException e) {
                        logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, e);
                    }
                }
                if (this.ignoreUrlPatternMatcherStrategyClass != null) {
                    this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);
                }
            }
            
            final Class gatewayStorageClass = getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS);

            if (gatewayStorageClass != null) {
                setGatewayStorage(ReflectUtils.newInstance(gatewayStorageClass));
            }
            
            final Class authenticationRedirectStrategyClass = getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS);

            if (authenticationRedirectStrategyClass != null) {
                this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass);
            }
        }
    }

    public void init() {
        super.init();
        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;

        //不拦截规则,添加如果访问路径为localLoginUrl且带有validated参数则跳过
        URL url = new URL(localLoginUrl);
        if (isRequestUrlExcluded(request) || request.getRequestURI().endsWith(url.getPath())) {
            logger.debug("Request is ignored.");
            filterChain.doFilter(request, response);
            return;
        }
        
        final HttpSession session = request.getSession(false);
        final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;

        if (assertion != null) {
            filterChain.doFilter(request, response);
            return;
        }

        final String serviceUrl = constructServiceUrl(request, response);
        final String ticket = retrieveTicketFromRequest(request);
        final boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);

        if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
            filterChain.doFilter(request, response);
            return;
        }

        final String modifiedServiceUrl;

        logger.debug("no ticket and no assertion found");
        if (this.gateway) {
            logger.debug("setting gateway attribute in session");
            modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
        } else {
            modifiedServiceUrl = serviceUrl;
        }

        logger.debug("Constructed service url: {}", modifiedServiceUrl);

        String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,
                getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);

        // 加入localLoginUrl
        urlToRedirectTo += (urlToRedirectTo.contains("?") ? "&" : "?") + "loginUrl=" + URLEncoder.encode(localLoginUrl, "utf-8");

        logger.debug("redirecting to \"{}\"", urlToRedirectTo);
        this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
    }

    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 setGatewayStorage(final GatewayResolver gatewayStorage) {
        this.gatewayStorage = gatewayStorage;
    }
        
    private boolean isRequestUrlExcluded(final HttpServletRequest request) {
        if (this.ignoreUrlPatternMatcherStrategyClass == null) {
            return false;
        }
        
        final StringBuffer urlBuffer = request.getRequestURL();
        if (request.getQueryString() != null) {
            urlBuffer.append("?").append(request.getQueryString());
        }
        final String requestUri = urlBuffer.toString();
        return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri);
    }

    public String getLocalLoginUrl() {
        return localLoginUrl;
    }

    public void setLocalLoginUrl(String localLoginUrl) {
        this.localLoginUrl = localLoginUrl;
    }
}


2)登录成功后,ST超时失效抛出异常解决,跳转到首页重新获取ST

修改:Cas20ServiceTicketValidator parseResponseFromServer 方法:

        //源码
//        final String error = XmlUtils.getTextForElement(response, "authenticationFailure");
//
//        if (CommonUtils.isNotBlank(error)) {
//            throw new TicketValidationException(error);
//        }
        //验证失败,返回自定义message,在AbstractTicketValidationFilter 中捕获,做为特殊的处理
        final String error = XmlUtils.getTextForElement(response,"authenticationFailure");
        if (CommonUtils.isNotBlank(error)) {
            throw new TicketValidationException("convicteva-TicketValidation-fail");
        }
修改 AbstractTicketValidationFilter 的doFilter 方法:

} catch (final TicketValidationException e) {
	//如果是票据验证失败,就跳转到请求的url
	if(e.getMessage().equalsIgnoreCase("convicteva-TicketValidation-fail")){
		response.sendRedirect(request.getRequestURL().toString());
		return;
	}

	response.setStatus(HttpServletResponse.SC_FORBIDDEN);

	logger.debug(e.getMessage(), e);

	onFailedValidation(request, response);

	if (this.exceptionOnValidationFailure) {
		throw new ServletException(e);
	}

	response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());

	return;
}


客户端demo工程
1)项目依赖


	org.jasig.cas.client
	cas-client-core
	3.4.1
2)web.xml 配置


    
    
        org.jasig.cas.client.session.SingleSignOutHttpSessionListener
    
    
    
        CAS Single Sign Out Filter
        org.jasig.cas.client.session.SingleSignOutFilter
        
            casServerUrlPrefix
            https://sso.convicteva.com:8443/cas
        
    
    
        CAS Single Sign Out Filter
        /*
    

    
    
        CASFilter
        org.jasig.cas.client.authentication.RemoteAuthenticationFilter
        
            casServerLoginUrl
            https://sso.convicteva.com:8443/cas/remoteLogin
        
        
            serverName
            http://www.convicteva.com:8888/demo/
        
        
            localLoginUrl
            http://www.convicteva.com:8888/demo/login/page
        
    
    
        CASFilter
        /*
    

    
    
        CAS_Validation_Filter
        
            org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
        
        
            casServerUrlPrefix
            https://sso.convicteva.com:8443/cas
        
        
            serverName
            http://www.convicteva.com:8888/demo
        
    

    
        CAS_Validation_Filter
        /*
    

    
    
        HttpServletRequestWrapperFilter
        
            org.jasig.cas.client.util.HttpServletRequestWrapperFilter
        
    

    
        HttpServletRequestWrapperFilter
        /*
    

    
    
        assertionThreadLocalFilter
        org.jasig.cas.client.util.AssertionThreadLocalFilter
    

    
        assertionThreadLocalFilter
        /*
    
    
	
	
	
        IndexServlet
        com.convicteva.sso.servlet.IndexServlet
    
    
        IndexServlet
        /
    
    
        loginServlet
        com.convicteva.sso.servlet.LoginServlet
    
    
        loginServlet
        /login/page
    

3)login.jsp
<%@ page language="java" pageEncoding="UTF-8"
         contentType="text/html; charset=UTF-8"%>



    
    登录


用户名:
密码:
验证码:
" id="errorCode"/>

4)index.jsp

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



    
    登录成功


您好:<%=request.getRemoteUser()%>


测试:
配置host:
127.0.0.1 sso.convicteva.com
127.0.0.1 www.convicteva.com

登录页面(www.convicteva.com:8888/demo/login/page):

cas源码改造-改造登录页面_第2张图片

登录成功:

cas源码改造-改造登录页面_第3张图片

登录成功后,访问cas,也是登录成功状态

cas源码改造-改造登录页面_第4张图片



修改代码:http://download.csdn.net/detail/convict_eva/9660148







你可能感兴趣的:(cas)