`
yeminping
  • 浏览: 181653 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

让CAS支持客户端自定义登陆页面——服务器篇

    博客分类:
  • JAVA
阅读更多

修改需要基于几个基本原则:

  1. 不影响原有统一登陆界面功能
  2. 客户端应尽量保持简单
  3. 尽量保证原有功能的完整性和安全性

对于第三点,必须事先说明:将登陆页面放到客户端本身就是降低了CAS安全性,这意味着作为服务向外发布的CAS服务器中的用户密码有可能由于客户端的不安全性而导致泄露,整个CAS系统成为了一个“水桶形态”,整个CAS体系的安全性将取决于所有客户端中安全性最低的一个 。这也是CAS官方一直不推荐的方式。

接下来我们讲解服务器端修改的详细过程:

首先,修改/WEB-INF/web.xml,为cas增加一个/remoteLogin的映射:

<servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/remoteLogin </url-pattern>
</servlet-mapping>

然后修改cas-servlet.xml文件,增加我们对/remoteLogin映射的处理,需要增加一个新流程:

<bean id="handlerMappingB" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/login">loginController</prop>
            <prop key="/remoteLogin">remoteController</prop>
        </props>
    </property>
    <property name="interceptors">
        <list>
            <ref bean="localeChangeInterceptor" />
        </list>
    </property>
</bean>

然后在cas-servlet.xml文件中添加我们上面所配置的remoteController的bean:

<!-- 增加远程控制者,允许以/remote请求启动remote控制流程 -->
<bean id="remoteLoginController"
    class="org.springframework.webflow.executor.mvc.FlowController"
    p:flowExecutor-ref="remoteLoginFlowExecutor"
    p:defaultFlowId="remoteLogin-webflow">
    <property name="argumentHandler">
        <bean
 class="org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler"
            p:flowExecutionKeyArgumentName="lt"
            p:defaultFlowId="remoteLogin-webflow" />
    </property>
</bean>
<flow:executor id="remoteLoginFlowExecutor" registry-ref="remoteLoginFlowRegistry">
    <flow:execution-attributes>
        <flow:alwaysRedirectOnPause value="false"/>
    </flow:execution-attributes>
</flow:executor>
<flow:registry id="remoteLoginFlowRegistry">
    <flow:location path="/WEB-INF/remoteLogin-webflow.xml "/>
</flow:registry>

可以看到上面将请求指向了webflow配置文件/WEB-INF/remoteLogin-webflow.xml文件,我们需要创建此文件并配置其成为我们所需的流程,以下是remoteLogin-webflow.xml全文:

<?xml version="1.0" encoding="UTF-8"?>
<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-1.0.xsd ">
    <start-state idref="remoteLogin"/>
    <!-- 远程登陆主要Action -->
    <action-state id="remoteLogin">
        <action bean="remoteLoginAction" />
        <transition on="error" to="remoteCallbackView" />
        <transition on="submit" to="bindAndValidate" />
        <transition on="checkTicketGrantingTicket" to="ticketGrantingTicketExistsCheck" />
    </action-state>
    <!-- 远程回调页面,主要以JavaScript的方式回传一些参数用 -->
    <end-state id="remoteCallbackView" view="remoteCallbackView" />
   
    <decision-state id="ticketGrantingTicketExistsCheck">
        <if test="${flowScope.ticketGrantingTicketId != null}" then="hasServiceCheck"
 else="gatewayRequestCheck" />
    </decision-state>
    <decision-state id="gatewayRequestCheck">
        <if test="${externalContext.requestParameterMap['gateway'] != '' &amp;&amp; externalContext.requestParameterMap['gateway'] != null &amp;&amp; flowScope.service != null}" then="redirect" else="remoteCallbackView " />
    </decision-state>
   
    <decision-state id="hasServiceCheck">
        <if test="${flowScope.service != null}" then="generateServiceTicket" else="remoteCallbackView " />
    </decision-state>
   
    <!--
        The "warn" action makes the determination of whether to redirect directly to the
 requested
        service or display the "confirmation" page to go back to the server.
    -->
    <decision-state id="warn">
        <if test="${flowScope.warnCookieValue}" then="showWarningView" else="redirect" />
    </decision-state>
    <action-state id="bindAndValidate">
        <action bean="authenticationViaFormAction" />
        <transition on="success" to="submit" />
        <transition on="error" to="remoteCallbackView " />
    </action-state>
   
    <action-state id="submit">
        <action bean="authenticationViaFormAction" method="submit" />
        <transition on="warn" to="warn" />
        <transition on="success" to="sendTicketGrantingTicket" />
        <transition on="error" to="remoteCallbackView " />
    </action-state>
   
    <action-state id="sendTicketGrantingTicket">
        <action bean="sendTicketGrantingTicketAction" />
        <transition on="success" to="serviceCheck" />
    </action-state>
    <decision-state id="serviceCheck">
        <if test="${flowScope.service != null}" then="generateServiceTicket"
 else="remoteCallbackView " />
    </decision-state>
   
    <action-state id="generateServiceTicket">
        <action bean="generateServiceTicketAction" />
        <transition on="success" to ="warn" />
        <transition on="error" to="remoteCallbackView " />
        <transition on="gateway" to="redirect" />
    </action-state>
    <!--
        The "showWarningView" end state is the end state for when the user has requested
 privacy settings (to be "warned") to be turned on.  It delegates to a
        view defines in default_views.properties that display the "Please click here to go
 to the service." message.
    -->
    <end-state id="showWarningView" view="casLoginConfirmView" />
    <!--
        The "redirect" end state allows CAS to properly end the workflow while still
 redirecting
        the user back to the service required.
    -->
    <end-state id="redirect" view="bean:dynamicRedirectViewSelector" />
   
    <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>

以上文件根据原login-webflow.xml文件修改,黄色背景为修改部分。可以看到,我们在流程中增加了remoteLogin Action节点和remoteCallback View节点,下面我们配置remoteLogin节点:
在/WEB-INF/cas-servlet.xml文件中增加remoteLoginAction配置:

<bean id="remoteLoginAction"
    class="com.baidu.cas.web.flow.RemoteLoginAction "
    p:argumentExtractors-ref="argumentExtractors"
    p:warnCookieGenerator-ref="warnCookieGenerator"
    p:ticketGrantingTicketCookieGenerator-ref="ticketGrantingTicketCookieGenerator" />

同时创建com.baidu.cas.web.flow.RemoteLoginAction类:

/**
 * 远程登陆票据提供Action.
 * 根据InitialFlowSetupAction修改.
 * 由于InitialFlowSetupAction为final类,因此只能将代码复制过来再进行修改.
 *
 * @author GuoLin
 */
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<ArgumentExtractor> 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("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<ArgumentExtractor> argumentExtractors) {
        this.argumentExtractors = argumentExtractors;
    }
}

以上黄色背景为修改部分,要求客户端必须传入loginUrl参数,且当客户端传入submit参数时,直接为其提交用户名密码
然后再配置remoteCallbackView显示节点,修改src/default_views.properties文件,增加remoteCallbackView配置:

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

创建/WEB-INF/view/jsp/default/ui/remoteCallbackView.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"% >
<html>
<head>
    <script type="text/javascript">
        var remoteUrl = "${remoteLoginUrl}?validated=true ";
        // 构造错误消息
        var errorMessage = "";
        <spring:hasBindErrors name="credentials">
        errorMessage = "&errorMessage=" + encodeURIComponent('<c:forEach
 var="error" items="${errors.allErrors}"><spring:message code="${error.code}"
 text="${error.defaultMessage}" /></c:forEach>');
        </spring:hasBindErrors>
       
        // 构造service
        var serivce = "";
        <c:if test="${service != null && service != ''}">
        service = "&service=" + encodeURIComponent("${service}");
        </c:if>
        // 跳转回去
        window.location.href = remoteUrl + errorMessage + service;
    </script>
</head>
<body>
    ${remoteLoginMessage}
</body>
</html>

以上文件注意黄色背景部分validated=true,这里我们与客户端约定,当客户端登陆页面后带有参数validated=true时,不进行票据认证请求。这是因为,客户端登陆页面为http://clienthost/login.jsp ,那么当用户访问URL  http://clienthost/login.jsp 时, 客户端会重定向到CAS中央服务器请求TGT认证,但认证失败后CAS中央认证服务器会重定向到客户端登陆页面并显示登陆框,此时客户端必须以某种规则避 免重新请求中央认证服务器认证,  在这里我们与客户端约定,当回发的请求为登陆页面且带有参数validated=true时即不转发TGT认证请求,即 http://
clienthost/login.jsp?validated=true 请求客户端不会重新发送TGT认证请求给中央认证服务器

 

 

http://fallenlord.blogbus.com/logs/36907044.html

分享到:
评论

相关推荐

    让CAS支持客户端自定义登陆页面——服务器篇.docx

    ### 让CAS支持客户端自定义登录页面——服务器篇 #### 概述 本文档主要介绍如何在CAS(Central Authentication Service)系统中实现客户端自定义登录页面的功能,并且着重讲解服务器端的修改步骤与注意事项。CAS...

    让CAS支持客户端自定义登陆页面——服务器篇[参考].pdf

    本文将详细介绍如何通过服务器端的配置,实现让CAS(Central Authentication Service,中央认证服务)支持客户端自定义登录页面的过程。这一过程不仅可以提升用户体验,还能够满足特定场景下的定制化需求。 ### ...

    让CAS支持客户端自定义登陆页面——客户端篇

    标题中的“让CAS支持客户端自定义登陆页面——客户端篇”表明了本文主要探讨的是如何在中央认证服务(Central Authentication Service, CAS)系统中,允许客户端应用程序实现自定义登录页面的配置与实现。...

    让CAS支持客户端自定义登陆页面----服务器篇--.doc

    【让CAS支持客户端自定义登陆页面——服务器篇】 CAS(Central Authentication Service)是一个开源的身份验证框架,它允许用户通过单一登录(Single Sign-On, SSO)访问多个应用系统。在某些场景下,用户可能希望...

    整合spring+springWebMVC+cas客户端

    5. **实现自定义登录页面**:根据需求创建自定义登录页面,通常会有一个链接引导用户到CAS服务器进行身份验证。 6. **处理服务验证**:CAS服务器验证用户身份后,会返回一个ticket,客户端需要验证这个ticket的有效...

    CAS客户端开发配置及其所需求的最基本的jar文件

    在开发CAS客户端时,确保客户端正确配置并与CAS服务器通信至关重要,以解决“即将定向不安全的连接”这类问题。 首先,理解CAS的基本工作原理:用户尝试访问受保护的资源时,会被重定向到CAS服务器进行身份验证。...

    JASIG CAS 3 Learning Note 1 -- getting started

    例如,你可以设置 CAS 服务器的端口号、服务验证的URL以及支持的认证协议。 接下来,为了实现单点登录,你需要在你的应用系统(客户端)中集成 CAS。这通常包括以下几个步骤: 1. **配置 CAS 客户端库**:在你的...

    cas server

    2. **CAS Server架构**:CAS Server的核心组件包括认证服务器、代理验证服务器和客户端。认证服务器处理用户的登录请求,验证用户凭证;代理验证服务器用于处理服务端的代理票证请求;客户端则是那些集成CAS服务的...

    基于Java的源码-单点登录系统 JA-SIG CAS.zip

    在本案例中,我们讨论的是基于Java实现的单点登录系统——JA-SIG CAS。这个系统是开源的,由教育高级网(Ja-Sig)开发,旨在提供一种简单而有效的解决方案,为校园环境或企业环境中的各种应用实现安全的单点登录功能...

    spring security2 安全手册(牛人写的)

    - **修改配置文件**:更新Spring Security配置以支持自定义登录页面。 - **登录页面中的参数配置**:设置登录表单所需的参数,如用户名和密码字段名称等。 - **测试一下**:验证自定义登录页面的功能是否正常工作。 ...

    spring security

    - **为 jetty 配置 Realm**: 配置 Jetty 服务器支持预先认证。 - **配置 Spring Security**: 在 Spring Security 中启用预先认证功能。 ##### 18. 切换用户 - **配置方式**: 配置切换用户功能。 - **实例演示**: ...

    PyPI 官网下载 | ftw.casauth-1.4.1.tar.gz

    1. CAS客户端支持:它实现了与CAS服务器的通信,包括票证验证、登录和登出操作。 2. 集成简单:该库易于集成到基于Python的Web应用程序中,如Flask和Django,通过提供中间件或装饰器,可以方便地添加CAS身份验证。 3...

    springsecurity3.x快速构建企业级安全

    ### Spring Security 3.x 快速构建企业级安全——关键知识点解析 #### 一、企业级安全概述 在《Spring Security 3.x 快速构建企业级安全》这本书中,作者罗时飞首先介绍了企业级安全的基本概念及其重要性。在现代...

    SpringSecurity 3.0.1.RELEASE.CHM

    21.3. 配置CAS客户端 22. X.509认证 22.1. 概述 22.2. 把X.509认证添加到你的web系统中 22.3. 为tomcat配置SSL 23. 替换验证身份 23.1. 概述 23.2. 配置 A. 安全数据库表结构 A.1. User表 A.1.1. 组权限 ...

    机顶盒功能介绍手册

    - **客户端**: 定期检查服务器更新信息,根据指令下载并安装。 - **安全措施**: 包括数据加密传输、签名验证等,以确保更新的安全性。 - **4.4 对于在线升级OTA模块的测试** - **测试内容**: 包括连接稳定性测试...

Global site tag (gtag.js) - Google Analytics