如何进入loginFlowRegistry流程
1、如何从”/”变为”/login”
在4.2.6源码包中的cas-server-webapp工程下,webapp\WEB-INF\目录下有个web.xml文件,其中有如下的配置。
*web.xml:*
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
- 1
- 2
- 3
- 4
由”/”转化为”index.jsp”页面,index.jsp页面在webapp\目录下。
*index.jsp:*
<%@ page language="java" session="false" %>
<%
final String queryString = request.getQueryString();
final String url = request.getContextPath() + "/login" + (queryString != null ? '?' + queryString : "");
response.sendRedirect(response.encodeURL(url));%>
- 1
- 2
- 3
- 4
- 5
- 6
如果对于是CAS客户端请求过来的地址,会被CAS客户端的过滤器进行封装后形成请求CAS单点登录服务端的重定向地址为如下格式:http://localhost:8080/cas/login?service=http%3A%2F%2Flocalhost%3A8088%2Fcas-client%2F。
但是在本文进行源码解读时,直接访问的是CAS单点登录服务端的地址,因此index.jsp中的queryString的值为空,所以会直接请求跳转到http://localhost:8080/cas/login地址。
2、如何映射login到CAS中,通过servlet-mapping到cas
在cas-server-webapp工程下,webapp\WEB-INF\目录下的web.xml文件。通过最基础的servlet进行相关的映射。
*web.xml:*
<servlet-mapping>
<servlet-name>cas</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
- 1
- 2
- 3
- 4
- 5
3、CAS把映射交给Spring的DispatcherServlet处理
我们知道CAS服务端是采用了Spring web flow来进行流程的处理,那么如何将servlet和Spring进行结合的。还是看web.xml配置文件。
*web.xml:*
<servlet>
<servlet-name>cas</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- Load the child application context. Start with the default, then modules, then overlays. -->
<param-value>/WEB-INF/cas-servlet.xml,classpath*:/META-INF/cas-servlet-*.xml,/WEB-INF/cas-servlet-*.xml</param-value>
</init-param>
<init-param>
<param-name>publishContext</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
请注意配置文件中的/WEB-INF/cas-servlet.xml这个配置文件。
4、解析cas-servlet.xml相关配置
我们目前关心的还是登录流程到底是怎么进行的,那么请看下面这段配置。
*cas-servlet.xml:*
<!-- login webflow configuration -->
<bean id="loginFlowHandlerMapping" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"
p:flowRegistry-ref="loginFlowRegistry" p:order="2">
<property name="interceptors">
<array value-type="org.springframework.web.servlet.HandlerInterceptor">
<ref bean="localeChangeInterceptor"/>
<ref bean="authenticationThrottle"/>
</array>
</property>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
从注释可以知道这是登录流程的入口配置,定义流程句柄bean为loginFlowHandlerMapping,流程为loginFlowRegistry。那么这个loginFlowRegistry属性是在哪里进行了定义呢?这个其实是在Spring相关的配置文件中进行配置的,那么我们继续看是如何解析Spring的配置文件的。
还是在web.xml文件中,我们看一下Spring的配置文件加载了哪一些。
*web.xml:*
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-configuration/*.xml
/WEB-INF/deployerConfigContext.xml
<!-- this enables extensions and addons to contribute to overall CAS' application context
by loading spring context files from classpath i.e. found in classpath jars, etc. -->
classpath*:/META-INF/spring/*.xml
</param-value>
</context-param>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
从上面的配置信息可以看出spring配置在/WEB-INF/spring-configuration/*.xml中。那么loginFlowRegistry这个是在哪里定义的呢,我们可以猜测这个应该是和webflow相关的,所以可以在Spring的配置文件下找到webflowContext.xml文件。
5、解析webflowContext.xml上下文配置
webflowContext.xml在/WEB-INF/spring-configuration/目录下。
*webflowContext.xml:*
<webflow:flow-registry id="loginFlowRegistry" flow-builder-services="builder" base-path="/WEB-INF/webflow">
<webflow:flow-location-pattern value="/login/*-webflow.xml"/>
</webflow:flow-registry>
< webflow:flow-registry 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-registry>
<webflow:flow-registry id=“logoutFlowRegistry” flow-builder-services=“builder” base-path="/WEB-INF/webflow">
<webflow:flow-location-pattern value="/logout/*-webflow.xml"/>
</webflow:flow-registry>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
定义了cas-servlet.xml 里登录Mapping对应的loginFlowRegistry,其流程配置文件/login/-webflow.xml即login-webflow.xml。同时还配置了退出流程logoutFlowRegistry,其配置文件/logout/-webflow.xml即logout-webflow.xml。
6、解析login-webflow.xml配置文件的初始化登录action
启动登录流程的是initialFlowSetupAction这个类。(具体解析login-webflow.xml文件请查看下一章节)
*login-webflow.xml:*
<var name=“credential” class=“org.jasig.cas.authentication.UsernamePasswordCredential”/>
<span class="token comment"><!--
<var name="credential" class="org.jasig.cas.authentication.RememberMeUsernamePasswordCredential" />
--></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>on-start</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>evaluate</span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>initialFlowSetupAction<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>on-start</span><span class="token punctuation">></span></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
7、登录流程处理HandlerAdapter
找到了登录流程,那么是如何通过/login进入此登录流程的呢?下面我们还是看/WEB-INF/cas-servlet.xml这个配置文件。
*cas-servlet.xml:*
<bean id="loginHandlerAdapter" class="org.jasig.cas.web.flow.SelectiveFlowHandlerAdapter"
p:supportedFlowId="login" p:flowExecutor-ref="loginFlowExecutor" p:flowUrlHandler-ref="loginFlowUrlHandler"/>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginFlowUrlHandler<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>org.jasig.cas.web.flow.CasDefaultFlowUrlHandler<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginFlowExecutor<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>org.springframework.webflow.executor.FlowExecutorImpl<span class="token punctuation">"</span></span>
<span class="token attr-name"><span class="token namespace">c:</span>definitionLocator-ref</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginFlowRegistry<span class="token punctuation">"</span></span>
<span class="token attr-name"><span class="token namespace">c:</span>executionFactory-ref</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginFlowExecutionFactory<span class="token punctuation">"</span></span>
<span class="token attr-name"><span class="token namespace">c:</span>executionRepository-ref</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginFlowExecutionRepository<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginFlowExecutionFactory<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>org.springframework.webflow.engine.impl.FlowExecutionImplFactory<span class="token punctuation">"</span></span>
<span class="token attr-name"><span class="token namespace">p:</span>executionKeyFactory-ref</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginFlowExecutionRepository<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
请注意loginHandlerAdapter这个配置的bean,其中的属性有supportedFlowId的值为“login”,同时属性flowExecutor-ref的引用值为loginFlowExecutor。再看loginFlowExecutor这个bean中所配置的登录流程属性引用值就是我们webflow上下文配置中的loginFlowRegistry这个属性。
因此我们来看一下loginHandlerAdapter这个bean对应的类为org.jasig.cas.web.flow.SelectiveFlowHandlerAdapter所起的作用,是如何来处理登录动作的。先来看一下这个类的父类org.springframework.webflow.mvc.servlet.FlowHandlerAdapter,这个是Springmvc中的一个类。
public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAdapter, InitializingBean {
- 1
FlowHandlerAdapter实现接口HandlerAdapter,而SelectiveFlowHandlerAdapter继承自FlowHandlerAdapter(如下)。SelectiveFlowHandlerAdapter类在cas-server-webapp-actions模块下的org.jasig.cas.web.flow包下。
因此Spring的DispatcherServlet找到要处理的handleAdapter是SelectiveFlowHandlerAdapte。而且根据地址http://localhost:8080/cas/login?service=XXX,得到handler的flowId=“login”,即流程:loginFlowRegistry,然后进入下面的handle方法,开始调取流程:
*org.jasig.cas.web.flow.SelectiveFlowHandlerAdapter.java*
public class SelectiveFlowHandlerAdapter extends FlowHandlerAdapter {
//此handle方法在父类中FlowHandlerAdapter中
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
FlowHandler flowHandler = (FlowHandler) handler;
checkAndPrepare(request, response, false);
//注意flowUrlHandler通过cas-servlet.xml中的配置类为//org.jasig.cas.web.flow.CasDefaultFlowUrlHandler,通过request来获取名称为
//“execution”的参数值,也就是flowExecutionKey。
String flowExecutionKey = flowUrlHandler.getFlowExecutionKey(request);
//对于第一请求跳转到登录页面,这个值为空,执行else中的代码
if (flowExecutionKey != null) {
try {
ServletExternalContext context = createServletExternalContext(request, response);
FlowExecutionResult result = flowExecutor.resumeExecution(flowExecutionKey, context);
handleFlowExecutionResult(result, context, request, response, flowHandler);
} catch (FlowException e) {
handleFlowException(e, request, response, flowHandler);
}
} else {
try {
//第一次访问,在配置文件中配置的flowId为“login”
String flowId = getFlowId(flowHandler, request);
MutableAttributeMap<Object> input = getInputMap(flowHandler, request);
ServletExternalContext context = createServletExternalContext(request, response);
//注意这里是最关键的点,加载登录流程的起始处,也就是通过这里把login-webflow.xml中//相关配置的流程走一遍。
FlowExecutionResult result = flowExecutor.launchExecution(flowId, input, context);
handleFlowExecutionResult(result, context, request, response, flowHandler);
} catch (FlowException e) {
handleFlowException(e, request, response, flowHandler);
}
}
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
如何进入loginFlowRegistry流程
1、如何从”/”变为”/login”
在4.2.6源码包中的cas-server-webapp工程下,webapp\WEB-INF\目录下有个web.xml文件,其中有如下的配置。
*web.xml:*
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
- 1
- 2
- 3
- 4
由”/”转化为”index.jsp”页面,index.jsp页面在webapp\目录下。
*index.jsp:*
<%@ page language="java" session="false" %>
<%
final String queryString = request.getQueryString();
final String url = request.getContextPath() + "/login" + (queryString != null ? '?' + queryString : "");
response.sendRedirect(response.encodeURL(url));%>
- 1
- 2
- 3
- 4
- 5
- 6
如果对于是CAS客户端请求过来的地址,会被CAS客户端的过滤器进行封装后形成请求CAS单点登录服务端的重定向地址为如下格式:http://localhost:8080/cas/login?service=http%3A%2F%2Flocalhost%3A8088%2Fcas-client%2F。
但是在本文进行源码解读时,直接访问的是CAS单点登录服务端的地址,因此index.jsp中的queryString的值为空,所以会直接请求跳转到http://localhost:8080/cas/login地址。
2、如何映射login到CAS中,通过servlet-mapping到cas
在cas-server-webapp工程下,webapp\WEB-INF\目录下的web.xml文件。通过最基础的servlet进行相关的映射。
*web.xml:*
<servlet-mapping>
<servlet-name>cas</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
- 1
- 2
- 3
- 4
- 5
3、CAS把映射交给Spring的DispatcherServlet处理
我们知道CAS服务端是采用了Spring web flow来进行流程的处理,那么如何将servlet和Spring进行结合的。还是看web.xml配置文件。
*web.xml:*
<servlet>
<servlet-name>cas</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- Load the child application context. Start with the default, then modules, then overlays. -->
<param-value>/WEB-INF/cas-servlet.xml,classpath*:/META-INF/cas-servlet-*.xml,/WEB-INF/cas-servlet-*.xml</param-value>
</init-param>
<init-param>
<param-name>publishContext</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
请注意配置文件中的/WEB-INF/cas-servlet.xml这个配置文件。
4、解析cas-servlet.xml相关配置
我们目前关心的还是登录流程到底是怎么进行的,那么请看下面这段配置。
*cas-servlet.xml:*
<!-- login webflow configuration -->
<bean id="loginFlowHandlerMapping" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"
p:flowRegistry-ref="loginFlowRegistry" p:order="2">
<property name="interceptors">
<array value-type="org.springframework.web.servlet.HandlerInterceptor">
<ref bean="localeChangeInterceptor"/>
<ref bean="authenticationThrottle"/>
</array>
</property>
</bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
从注释可以知道这是登录流程的入口配置,定义流程句柄bean为loginFlowHandlerMapping,流程为loginFlowRegistry。那么这个loginFlowRegistry属性是在哪里进行了定义呢?这个其实是在Spring相关的配置文件中进行配置的,那么我们继续看是如何解析Spring的配置文件的。
还是在web.xml文件中,我们看一下Spring的配置文件加载了哪一些。
*web.xml:*
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-configuration/*.xml
/WEB-INF/deployerConfigContext.xml
<!-- this enables extensions and addons to contribute to overall CAS' application context
by loading spring context files from classpath i.e. found in classpath jars, etc. -->
classpath*:/META-INF/spring/*.xml
</param-value>
</context-param>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
从上面的配置信息可以看出spring配置在/WEB-INF/spring-configuration/*.xml中。那么loginFlowRegistry这个是在哪里定义的呢,我们可以猜测这个应该是和webflow相关的,所以可以在Spring的配置文件下找到webflowContext.xml文件。
5、解析webflowContext.xml上下文配置
webflowContext.xml在/WEB-INF/spring-configuration/目录下。
*webflowContext.xml:*
<webflow:flow-registry id="loginFlowRegistry" flow-builder-services="builder" base-path="/WEB-INF/webflow">
<webflow:flow-location-pattern value="/login/*-webflow.xml"/>
</webflow:flow-registry>