cas 登陆和登出是基于spring web flow 的,如果不了解 spring web flow 是没办法修改的,所以在修改cas 的登陆时最好先了解一下 spring web flow。
下边说一下简单的修改:
1、先将target下的 webflow 文件夹拷贝到 WEB-INF下
2、登陆流程简单的说明:
打开 其中login下的login-webflow.xml,并找到下边的代码:
<view-state id="viewLoginForm" view="casLoginView" model="credential">
<binder>
<binding property="username" required="true"/>
<binding property="password" required="true"/>
<!--
<binding property="rememberMe" />
-->
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credential'"/>
<!--
<evaluate expression="samlMetadataUIParserAction" />
-->
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit"/>
</view-state>
看这段代码的最后一句:<transition on="submit" bind="true" validate="true" to="realSubmit"/>,这句的大概意思就是当点击submit按钮之后,进入 realSubmit流程。这里就是登陆验证所以动作的开始!!
既然如此,我们在去找realSubmit:
<action-state id="realSubmit">
<evaluate
expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credential, messageContext)"/>
<transition on="warn" to="warn"/>
<!--
To enable AUP workflows, replace the 'success' transition with the following:
<transition on="success" to="acceptableUsagePolicyCheck" />
-->
<transition on="success" to="sendTicketGrantingTicket"/>
<transition on="successWithWarnings" to="showMessages"/>
<transition on="authenticationFailure" to="handleAuthenticationFailure"/>
<transition on="error" to="initializeLogin"/>
</action-state>
解释一下这段代码:
evaluate:可以理解为realSubmit这个流程里边的核心处理代码,authenticationViaFormAction:这个是具体处理的action,它是AuthenticationViaFormAction 类的注解,这个可以在源码里去找。最通俗话就是点击页面登陆之后,程序就进入AuthenticationViaFormAction 类的submit方法验证登陆了。
下边的transition 代表处理的不同结果,进入不同的下一个流程。如果验证成功就进入sendTicketGrantingTicket。然后我们再去找sendTicketGrantingTicket,sendTicketGrantingTicket处理成功之后就进入
<decision-state id="serviceCheck">
<if test="flowScope.service != null" then="generateServiceTicket" else="viewGenericLoginSuccess"/>
</decision-state>
这里有一个判断,flowScope.service里边封装的是客户端请求的url,如果它不是是空的就进入 generateServiceTicket 否则进入viewGenericLoginSuccess,依次类推,整个步骤就是这样了。
3、自定义流程:
默认的登陆流程是最基础的,有两种方式实现自定义流程,第一、我们可以在realSubmit之前添加一个或者多个自己写的流程,第二直接修改realSubmit的evaluate让登陆验证指向我们自己写的验证代码(这种方式需要参考源码去写,比如返回的key得跟transition 中on属性一致等等)。
不管是哪种方式,我们都需要自己去写局部或者整体的验证代码,步骤如下:
a、在根目录下创建包org.jasig.cas,因为cas注解扫描是从这个包开始的,这个可以在spring-configuration里找到(项目里没有说明你没有将其从target中拷贝上来,去target里去找就行了),源码是:
<context:component-scan base-package="org.jasig.cas" />
这个不能改!!如果改成自己的包路径,它就无法解析别的了。
b、创建自己的验证action:
package org.jasig.cas.login;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.authentication.Credential;
import org.jasig.cas.web.support.WebUtils;
import org.springframework.binding.message.MessageContext;
import org.springframework.stereotype.Component;
import org.springframework.webflow.execution.RequestContext;
import com.demo.login.UsernamePasswordVCodeCredential;
@Component("authenticationViaFormVCodeAction")
public class AuthenticationViaFormVCodeAction {
//添加自定义验证方法1
public final String validatorCode(RequestContext flowRequestContext,Credential credential,MessageContext messageContext) throws Exception {
System.out.println("进入了自定义验证逻辑!!!!");
//这里可以写自己的验证逻辑,比如验证码之类的。
return "success";
}
//添加自定义验证方法2
public String goSys(RequestContext flowRequestContext,Credential credential,MessageContext messageContext) throws Exception {
HttpServletResponse response = WebUtils.getHttpServletResponse(flowRequestContext);
UsernamePasswordVCodeCredential ucredential = (UsernamePasswordVCodeCredential)credential;
//response.sendRedirect(ucredential.getSys_url());
return ucredential.getSys_url();
}
}
c、添加或者修改流程
如果修改realSubmit,只需要修改一下evaluate指向,上边已经说过。
如果在realSubmit之前添加一个新的流程:
在login-webflow.xml中添加一个action-state,让它指向我们自己的验证逻辑代码,并设置transition ,如果成功进入realSubmit,失败进入initializeLogin(重新初始化登陆页)例如:
<!-- 自定义验证 -->
<action-state id="vCodeValidate">
<evaluate expression="authenticationViaFormVCodeAction.validatorCode(flowRequestContext, flowScope.credential, messageContext)" />
<transition on="error" to="initializeLogin" />
<transition on="success" to="realSubmit" />
</action-state>
然后将点击登陆后的处理流程指向它:
<view-state id="viewLoginForm" view="casLoginView" model="credential">
<binder>
<binding property="username" required="true"/>
<binding property="password" required="true"/>
<!--
<binding property="rememberMe" />
-->
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credential'"/>
<!--
<evaluate expression="samlMetadataUIParserAction" />
-->
</on-entry>
<transition on="submit" bind="true" validate="true" to="vCodeValidate"/>
</view-state>
以上就基本实现了自定义登陆了。
4、添加验证参数
实际项目中可能要验证的不止是用户名和密码,还需要有角色啊什么的,这时就需要增加参数。
看上边的代码,很明显<binding property="password" required="true"/>这个就是我们的参数了,所以我们要增加参数也需要在这里配置,但是如果我们直接在这个后边添加上新的参数,在后台并没有获取到,原因是 默认的实体类配置的是:
<var name="credential" class="org.jasig.cas.authentication.UsernamePasswordCredential"/>
org.jasig.cas.authentication.UsernamePasswordCredential这个类里边只有用户名和密码,所以肯定是取不到的,所以我们要创建自己的实体类,并让它继承这个UsernamePasswordCredential,然后把新的属性加进去就行了,例如:
package com.demo.login;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.jasig.cas.authentication.UsernamePasswordCredential;
public class UsernamePasswordVCodeCredential extends UsernamePasswordCredential{
@NotNull
@Size(
min=1,
message = "required.sys_url"
)
private String sys_url;
public String getSys_url() {
return sys_url;
}
public void setSys_url(String sys_url) {
this.sys_url = sys_url;
}
}
这样就新加了一个 一个sys_url 参数进去,然后将配置原来的实体类代码注释掉,换成新的自定义实体类:
<!--默认的-->
<!-- <var name="credential" class="org.jasig.cas.authentication.UsernamePasswordCredential"/> -->
<!--新的-->
<var name="credential" class="com.demo.login.UsernamePasswordVCodeCredential"/>
再把新增的属性添加都password后边,例如:
<binding property="password" required="true"/>
<binding property="sys_url" required="true"/>
...
最后页面上添加一个 name=sys_url的input即可,例如:
<input type="hidden" id="sys_url" name="sys_url" value="http://127.0.0.1:8081/prdicman" />
后台获取的时候只需要转义一下:
UsernamePasswordVCodeCredential ucredential = (UsernamePasswordVCodeCredential)credential;
即可。
总结:
修改登陆流程,首先要了解spring web flow只要了解了spring web flow,那么我们就可以随意去修改了,这里只需要注意的是将新的验证代码放到org.jasig.cas路径下边,让Spring能装载到就行了。