CAS 6.2.2 中的 WebFlow

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CAS 6.2.2 中的 WebFlow相关的知识,希望对你有一定的参考价值。

参考技术A WebFlow 请求的入口如下图,向Spring mvc注册一个接口适配器

流程的读取

cas-server-core-webflow-api:6.2.2 org.apereo.cas.web.flow.configurer.DefaultLoginWebflowConfigurer

当状态为初始化状态时,会执行 initialAuthenticationRequestValidationAction 动作 和 verifyRequiredServiceAction 动作

使用spring webflow,在前台页面中如何显示后端返回的错误信息

刚刚接触spring webflow,相关的资料并不是很多,并且大都是那种入门的 .xml文件的配置。

用到的CAS 最新的4.0版本用的就是web-flow流,前台页面使用的是表单提交。于是我就碰到了一个问题,问题描述如下:

第一次输入错误的用户名密码提示用户名密码错误,第二次输入了正确的用户名和密码仍然报错,校验不通过。

在使用cas之前的登录页面如果输入用户名和密码错误的话,会弹出alert提示框,这个是使用ajax请求实现的。而ajax请求的一般都是那种spring mvc的controller,并且可以异步根据返回值回掉。但是cas的源码里面使用的是表单提交,表单提交不是异步的,所以除非加iframe,否则没法回调函数来刷新页面。而加了iframe之后也存在许多的改动,后续的工作量也不可评估。(为什么一定要回调呢,因为cas的页面表单里不只有用户名和密码输入框,还有个讨厌的隐藏元素:loginticket 和 flowExecutionKey,cas处理每次请求都需要重新生成一个 loginticket票据)。

想过几种解决方案,刚开始都是想webflow和mvc整合,两种方式:

1. 将login-webflow.xml中的end-state标签中的externalRedirect修改成我的某个controller并在参数里面带上错误信息,controller返回一个对象给到前端(一般是code:-1;msg:"";date:****这样的json串的形式)。那么前端ajax调用login这个webflow的时候,就会重定向到我定义的这个controller,并且拿到这个controller的返回值进行回调。

<end-state id="redirectView" view="externalRedirect:http://user/res?code=-1&msg="error"" />

但是这样有一个问题,弹出alert框之后点击确定,alert框消失了,再重新输入正确的用户名和密码,仍然会报错,原因是loginticket验证失败。关于loginticket校验的,可以从cas的源码中看到:

AuthenticationViaFormAction:
public final Event submit(final RequestContext context, final Credential credential,
            final MessageContext messageContext) throws Exception {
        // Validate login ticket
        final String authoritativeLoginTicket = WebUtils.getLoginTicketFromFlowScope(context);
        final String providedLoginTicket = WebUtils.getLoginTicketFromRequest(context);
        if (!authoritativeLoginTicket.equals(providedLoginTicket)) {
            logger.warn("Invalid login ticket {}", providedLoginTicket);
            messageContext.addMessage(new MessageBuilder().code("error.invalid.loginticket").build());
            return newEvent(ERROR);
        }
……

是去拿flow流中的lt和请求中的票据lt进行比较的。然而表单中的票据没有更新成最新的,我的webflow结束之后才返回的错误信息,那自然拿不到webflow里面生成的票据了。

先抛开这个问题不谈,说第二种整合mvc的方法:

在end-state标签中加入output,output中输出一个对像;

第三种:继承AbstractFlowHandler方法,

public class OcLoginFlowEndHandler extends AbstractFlowHandler {
    public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
            HttpServletResponse response) {
        if (outcome.getId().equals("redirectView")) {
            return "/user/loginRes?code=" + outcome.getOutput().get("bookingId");
        } else {
            return "/hotels/index";
        }
    }
}

然而这都没有解决我的问题。因为出了那个webflow容器拿到的lt总是不对的。

那怎么在login-webflow这个闭环中返回错误信息给前台页面呢?

查到有一种方式:http://docs.spring.io/spring-webflow/docs/2.3.x/reference/htmlsingle/#end-state-element

使用一个viewstate,来展示popup 对话框:

?<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">

不过这个加了这个viewstate之后也得重新定向到login的viewstate才行。

最后我采用的方案:

修改login的viewstate:

    <view-state id="viewLoginForm" view="/platform/login" model="credential">
        <binder>
            <binding property="username" />
            <binding property="password" />
        </binder>
        <on-entry>
            <set name="requestScope.messages" value="messageContext.allMessages" />
            <set name="viewScope.commandName" value="‘credential‘" />
        </on-entry>
        <transition on="submit"  bind="true" validate="true" to="realSubmit">
            <evaluate
                expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credential)" />
        </transition>
    </view-state>

添加绿色的那一行,这个view在render到velocity页面的时候,直接把requestScope里的messages给放进去,前端控制,如果messages为空,就不展示,如果不为空,就展示出来。

<label style="float: left; display: inline-block; font-size: 12px; color: red; text-decoration: none; margin: 5px 0;">
                                    #foreach(${message} in ${messages} )
                                    #if(${message.text} == "Invalid credentials.")
                                        用户名、密码或验证码错误!
                                    #end
                                    #end
                                    </label>

done!

那么看下效果:

技术分享

再输入正确的用户名和密码就不会报那个loginticket验证失败的错误并且能成功登录到系统中去了。

不足的是,其实很明显的看到页面刷新了一下。

 

 

 

 

 

 

 

 

 

以上是关于CAS 6.2.2 中的 WebFlow的主要内容,如果未能解决你的问题,请参考以下文章

Java——聊聊JUC中的CAS原理

Java——聊聊JUC中的CAS原理

Java——聊聊JUC中的CAS原理

JAVA锁中的CAS

JAVA锁中的CAS

REST API 中的 CAS