单点登录(二):原理代码分析
来源:互联网 发布:7u分享网络微信打不开 编辑:程序博客网 时间:2024/04/30 05:35
用户第一次发送请求--->CAS客户端转发至CAS服务器---->CAS服务器返回登录页--->用户登录(输入帐号密码)发送至CAS服务器----->CAS服务器认证------>重定向目标资源。
1.4 请求路径
2.3工作流处理请求流程
一.用户第一次发送请求----->CAS客户端转发
当用户第一次访问子系统A的时候,由于在子系统A配置了过滤器,所以首先会对请求进行拦截,如下web.xml代码:
<filter-name>CAS Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://iot:8443/casServer/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://iot:18080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
1.2 过滤器doFilter()具体操作
final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
if (assertion != null) {
filterChain.doFilter(request, response);
return;
如图所示:
1.4 请求路径
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://iot:8443/casServer/login</param-value>
在CAS中MVC的控制主要是使用的spring MVC来实现的。但是,在登录过程中,因为有点类似于工作流的性质,所以,采用了一个轻量级的工作流框架,就是spring 的weflow。
<servlet-class>
org.jasig.cas.web.init.SafeDispatcherServlet
</servlet-class>
<servlet-mapping>
<url-pattern>/login</url-pattern>
</servlet-mapping>
那么,在org.jasig.cas.web.init.SafeDispatcherServlet类中:
throws ServletException, IOException {
if (this.initSuccess) {
this.delegate.service(req, resp);
} else {
throw new ApplicationContextException(
"Unable to initialize application context.");
}
Spring MVC核心配置文件是cas-servlet.xml。在该文件中,webflow将与springMVC进行集成。这里有一个问题,就是spring何时开始加载cas-servlet.xml文件的呢?原来,在初始化DispatcherServlet的时候,会自动加载 servlet-name+“-servlet.xml”文件。所以,cas-servlet.xml是自动加载的,不需要在配置文件进行配置。(参见关于springMVC的文章)
交给spring MVC之后,spring MVC又将请求交给了 webflow处理。<webflow:flow-execution-attributes>
<webflow:always-redirect-on-pause value="false"/>
<webflow:redirect-in-same-state value="false" />
</webflow:flow-execution-attributes>
<webflow:flow-execution-listeners>
<webflow:listener ref="terminateWebSessionListener" />
</webflow:flow-execution-listeners>
</webflow:flow-executor>
<webflow:flow-registry id="flowRegistry" flow-builder-services="builder">
<webflow:flow-location path="/WEB-INF/login-webflow.xml" id="login"/>
</webflow:flow-registry>
<webflow:flow-builder-services id="builder" view-factory-creator="viewFactoryCreator"
在该文件中,我们可以看到上面的配置项。这就是将webflow框架作为spring MVC的一个节点来进行配置。webflow:flow-registry节点就是注册了一个webflow流程,该流程的入口,也就是ID=“login”。这样,交给springMVC的请求路径如果是login的,则有springMVC交给webflow处理。
在webflow中,会定义一些视图,这些视图都是以view=”XXX”的形式存在的。那么XXX又是如何找到对应的页面呢??看flow-builder-services节点,我们会发现有个view-factory-creator属性,该属性就定义了视图解析工厂。
该视图解析工厂是由视图解析器组成的。这里只定义了一个视图解析器,就是viewResolvers。该视图解析器是springFramework中的ResourceBundleViewResolver的一个实例,该类可以通过basenames属性,找到value值对应的properties属性文件,该文件中式类似ke=values类型的内容,正是该文件将jsp文件映射成视图名称。
至此,springMVC与webflow已经集成完毕。
2.3工作流处理请求流程
1.首先判断有无TGT,没有所以去到gatewayRequestCheck节点中,如下代码:
<if test="flowScope.ticketGrantingTicketId != null" then="hasServiceCheck" else="gatewayRequestCheck" />
2.然后再判断有没有requestParameters.gateway,首次访问flowScope.service为false,那么就会来到serviceAuthorizationCheck节点,如下代码:
<if test="requestParameters.gateway != '' and requestParameters.gateway != null and flowScope.service != null" then="gatewayServicesManagementCheck" else="serviceAuthorizationCheck" />
3.接着在serviceAuthorizationCheck,转去用generateLoginTicket节点进行处理,如下代码:
<evaluate expression="serviceAuthorizationCheck"/>
<transition to="generateLoginTicket"/>
4.接着在generateLoginTicket中,使用generateLoginTicketAction类中的genetate()方法进行处理。处理完后,如果返回"genetated",则进入viewLoginForm节点,如下代码:
<evaluate expression="generateLoginTicketAction.generate(flowRequestContext)" />
<transition on="generated" to="viewLoginForm" />
<view-state id="viewLoginForm" view="casLoginView" model="credentials">
<binder>
<binding property="username" />
<binding property="password" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credentials'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
</transition>
三.用户登录(输入帐号密码)发送----->CAS服务器认证
<view-state id="viewLoginForm" view="casLoginView" model="credentials">
<binder>
<binding property="username" />
<binding property="password" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credentials'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
</transition>
</view-state>
<evaluate expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credentials, messageContext)" />
<transition on="warn" to="warn" />
<transition on="success" to="sendTicketGrantingTicket" />
<transition on="error" to="generateLoginTicket" />
<transition on="accountDisabled" to="casAccountDisabledView" />
<transition on="mustChangePassword" to="casMustChangePassView" />
<transition on="accountLocked" to="casAccountLockedView" />
<transition on="badHours" to="casBadHoursView" />
<transition on="badWorkstation" to="casBadWorkstationView" />
<transition on="passwordExpired" to="casExpiredPassView" />
</action-state>
3.2.1 验证流水号
final String authoritativeLoginTicket = WebUtils.getLoginTicketFromFlowScope(context);
final String providedLoginTicket = WebUtils.getLoginTicketFromRequest(context);
if (!authoritativeLoginTicket.equals(providedLoginTicket)) {
this.logger.warn("Invalid login ticket " + providedLoginTicket);
final String code = "INVALID_TICKET";
messageContext.addMessage(
new MessageBuilder().error().code(code).arg(providedLoginTicket).defaultText(code).build());
return "error";
在这个submit方法的最后,有一个语句,这个语句就是完成认证的:
WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials));
其中credentials包含了用户输入的信息,比如用户名,密码等。
在this.centralAuthenticationService.createTicketGrantingTicket(credentials)完成认证,认证不过是会抛异常的。
注意:
2.CentralAuthenticationService 是一个接口,CentralAuthenticationServiceImpl是其实现类。
去到这个类的这个方法,看看是怎么实现的。
Assert.notNull(credentials, "credentials cannot be null");
try {
final Authentication authentication = this.authenticationManager
.authenticate(credentials);
final TicketGrantingTicket ticketGrantingTicket = new TicketGrantingTicketImpl(
this.ticketGrantingTicketUniqueTicketIdGenerator
.getNewTicketId(TicketGrantingTicket.PREFIX),
authentication, this.ticketGrantingTicketExpirationPolicy);
this.ticketRegistry.addTicket(ticketGrantingTicket);
return ticketGrantingTicket.getId();
} catch (final AuthenticationException e) {
throw new TicketCreationException(e);
}
this.authenticationManager .authenticate(credentials);中的this.authenticationManager在本类中没有定义,但是有其注入函数,注释可知是由springmvc注入,如下代码:
* Method to inject the AuthenticationManager into the class.
* @param authenticationManager The authenticationManager to set.
*/
public void setAuthenticationManager(
final AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
<property name="credentialsToPrincipalResolvers">
<property name="authenticationHandlers">
<list>
<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:httpClient-ref="httpClient" />
Ps:在SimpleTestUsernamePasswordAuthenticationHandler类中,有如下具体验证代码:
if (StringUtils.hasText(username) && StringUtils.hasText(password)
&& username.equals(getPasswordEncoder().encode(password)))
总结:
那么这句话认证通过后,就会执行下面的两句话,
1.putWarnCookieIfRequestParameterPresent(context);
2.return "success";
- 单点登录(二):原理代码分析
- 单点登录(一):原理分析
- 单点登录(一):原理分析
- 单点登录(一):原理分析
- CAS单点登录原理分析
- CAS实现单点登录(sso)原理分析
- tomcat 单点登录 SSO 原理分析
- 单点登录(SSO)原理
- 单点登录设计原理
- CAS 单点登录原理
- 单点登录 原理
- 单点登录应用原理
- 单点登录SSO原理
- 单点登录原理
- SSO单点登录原理
- 单点登录设计原理
- 单点登录设计原理
- cas单点登录原理
- Opencv2.4.9源码分析——SURF
- SnappyDB—Android上的NoSQL数据库
- 第5题:矩阵翻转
- mySQL中replace的用法
- 字符串
- 单点登录(二):原理代码分析
- 黑马程序员_网络编程(三)
- 如何将一个JavaEE项目打包成War文件
- ASP.NET购物车 - Ferry - 博客园
- 逆向/安全工具 小技巧 (整理)
- 数据结构课程设计(题2)
- Android Intent中的FLAG,很全
- 在table中tr的display:block在firefox下显示布局错乱问题
- 行内元素和块级元素