CAS SSO改造步骤4(重构)


前面三篇文章里面提到的由于对源码做了改动,这对开源程序是一种损害。故在前面的基础之上,将原先的代码重构,完全解耦,另外又重新阅读了login-webflow.xml 的逻辑,只在配置文件中引入自己写的类,实现SSO单点登录的功能。

改动之处主要在:

  1. <span style="font-family:SimHei;font-size:18px;">  
  2.   
  3.     <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />  
  4.     <on-start>  
  5.         <evaluate expression="initialFlowSetupAction" />  
  6.     </on-start>  
  7.   
  8.     <decision-state id="ticketGrantingTicketExistsCheck">  
  9.         <if test="flowScope.ticketGrantingTicketId neq null" then=<span style="color:#CCFFFF;"><span style="color:#000000;"><span style="background-color: rgb(102, 255, 255);">"hasServiceCheck"</span></span> </span>else="gatewayRequestCheck" />  
  10.     </decision-state>  
  11.       
  12.     <decision-state id="gatewayRequestCheck">  
  13.         <if test="externalContext.requestParameterMap['gateway'] neq '' && externalContext.requestParameterMap['gateway'] neq null && flowScope.service neq null" then="gatewayServicesManagementCheck" else="generateLoginTicket" />  
  14.     </decision-state>  
  15.       
  16.     <decision-state id=<span style="background-color: rgb(102, 255, 255);">"hasServiceCheck"</span>>  
  17.         <span style="color:#FF0000;"><on-entry>  
  18.             <evaluate expression="serviceRegisterCheck.doChangeStatus(flowRequestContext)" />  
  19.         </on-entry></span>  
  20.         <if test="flowScope.service != null" then="renewRequestCheck" else="viewGenericLoginSuccess" />  
  21.     </decision-state>  
  22.       
  23.     <decision-state id="renewRequestCheck">  
  24.         <if test="externalContext.requestParameterMap['renew'] neq '' && externalContext.requestParameterMap['renew'] neq null" then="generateLoginTicket" else=<span style="background-color: rgb(102, 255, 255);">"serviceRegisterCheck"</span> />  
  25.     </decision-state>  
  26.       
  27.     <!--   
  28.         The "warn" action makes the determination of whether to redirect directly to the requested  
  29.         service or display the "confirmation" page to go back to the server.  
  30.     -->  
  31.     <decision-state id="warn">  
  32.         <if test="flowScope.warnCookieValue" then="showWarningView" else="redirect" />  
  33.     </decision-state>  
  34.     <span style="color:#CC0000;"><action-state id=<span style="background-color: rgb(102, 255, 255);">"serviceRegisterCheck"</span>>  
  35.         <span style="color:#330099;"><evaluate expression="serviceRegisterCheck.doCheckRedirection(flowRequestContext)" /></span>  
  36.         <transition on="success" to="generateServiceTicket"/>  
  37.         <transition on="error" to="viewServiceErrorView"/>  
  38.     </action-state></span>  
  39.     <!--   
  40.     <action-state id="startAuthenticate">  
  41.         <action bean="x509Check" />  
  42.         <transition on="success" to="sendTicketGrantingTicket" />  
  43.         <transition on="warn" to="warn" />  
  44.         <transition on="error" to="generateLoginTicket" />  
  45.     </action-state>  
  46.      -->  
  47.       
  48.     <action-state id="generateLoginTicket">  
  49.         <evaluate expression="generateLoginTicketAction.generate(flowRequestContext)" />  
  50.         <transition on="success" to="viewLoginForm" />  
  51.     </action-state>  
  52.       
  53.     <view-state id="viewLoginForm" view="casLoginView" model="credentials">  
  54.         <binder>  
  55.             <binding property="username" />  
  56.             <binding property="password" />  
  57.         </binder>  
  58.         <on-entry>  
  59.             <set name="viewScope.commandName" value="'credentials'" />  
  60.         </on-entry>  
  61.         <transition on="submit" bind="true" validate="true" to="loginServiceCheck">  
  62.             <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />  
  63.         </transition>  
  64.     </view-state>  
  65.     <span style="color:#FF6600;"><action-state id="loginServiceCheck">  
  66.                <span style="color:#000099;"> <evaluate expression="serviceRegisterCheck.doCheckURL(flowRequestContext,flowScope.credentials)" /></span>  
  67.         <transition on="success" to="realSubmit"/>  
  68.         <transition on="error" to="viewServiceErrorView"/>  
  69.     </action-state></span>  
  70.     <action-state id="realSubmit">  
  71.         <evaluate expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credentials, messageContext)" />  
  72.         <transition on="warn" to="warn" />  
  73.         <transition on="success" to="sendTicketGrantingTicket" />  
  74.         <transition on="error" to="generateLoginTicket" />  
  75.     </action-state>  
  76.   
  77.     <action-state id="sendTicketGrantingTicket">  
  78.         <evaluate expression="sendTicketGrantingTicketAction" />  
  79.         <transition to="serviceCheck" />  
  80.     </action-state>  
  81.   
  82.     <decision-state id="serviceCheck">  
  83.         <if test="flowScope.service neq null" then="generateServiceTicket" else="viewGenericLoginSuccess" />  
  84.     </decision-state>  
  85.       
  86.     <action-state id="generateServiceTicket">  
  87.         <evaluate expression="generateServiceTicketAction" />  
  88.         <transition on="success" to ="warn" />  
  89.         <transition on="error" to="generateLoginTicket" />  
  90.         <transition on="gateway" to="gatewayServicesManagementCheck" />  
  91.     </action-state>  
  92.   
  93.     <action-state id="gatewayServicesManagementCheck">  
  94.         <evaluate expression="gatewayServicesManagementCheck" />  
  95.         <transition on="success" to="redirect" />  
  96.     </action-state>  
  97.   
  98.     <action-state id="redirect">  
  99.         <evaluate expression="flowScope.service.getResponse(requestScope.serviceTicketId)" result-type="org.jasig.cas.authentication.principal.Response" result="requestScope.response" />  
  100.         <transition to="postRedirectDecision" />  
  101.     </action-state>  
  102.   
  103.      
  104. </span>  


    <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />
    <on-start>
        <evaluate expression="initialFlowSetupAction" />
    </on-start>

	<decision-state id="ticketGrantingTicketExistsCheck">
		<if test="flowScope.ticketGrantingTicketId neq null" then="hasServiceCheck" else="gatewayRequestCheck" />
	</decision-state>
    
	<decision-state id="gatewayRequestCheck">
		<if test="externalContext.requestParameterMap['gateway'] neq '' && externalContext.requestParameterMap['gateway'] neq null && flowScope.service neq null" then="gatewayServicesManagementCheck" else="generateLoginTicket" />
	</decision-state>
	
	<decision-state id="hasServiceCheck">
		<on-entry>
			<evaluate expression="serviceRegisterCheck.doChangeStatus(flowRequestContext)" />
		</on-entry>
		<if test="flowScope.service != null" then="renewRequestCheck" else="viewGenericLoginSuccess" />
	</decision-state>
	
	<decision-state id="renewRequestCheck">
		<if test="externalContext.requestParameterMap['renew'] neq '' && externalContext.requestParameterMap['renew'] neq null" then="generateLoginTicket" else="serviceRegisterCheck" />
	</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="serviceRegisterCheck">
		<evaluate expression="serviceRegisterCheck.doCheckRedirection(flowRequestContext)" />
		<transition on="success" to="generateServiceTicket"/>
		<transition on="error" to="viewServiceErrorView"/>
	</action-state>
	<!-- 
	<action-state id="startAuthenticate">
		<action bean="x509Check" />
		<transition on="success" to="sendTicketGrantingTicket" />
		<transition on="warn" to="warn" />
		<transition on="error" to="generateLoginTicket" />
	</action-state>
	 -->
  	
	<action-state id="generateLoginTicket">
        <evaluate expression="generateLoginTicketAction.generate(flowRequestContext)" />
		<transition on="success" to="viewLoginForm" />
	</action-state>
    
	<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="loginServiceCheck">
            <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
        </transition>
	</view-state>
	<action-state id="loginServiceCheck">
                <evaluate expression="serviceRegisterCheck.doCheckURL(flowRequestContext,flowScope.credentials)" />
		<transition on="success" to="realSubmit"/>
		<transition on="error" to="viewServiceErrorView"/>
	</action-state>
	<action-state id="realSubmit">
        <evaluate expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credentials, messageContext)" />
		<transition on="warn" to="warn" />
		<transition on="success" to="sendTicketGrantingTicket" />
		<transition on="error" to="generateLoginTicket" />
	</action-state>

	<action-state id="sendTicketGrantingTicket">
        <evaluate expression="sendTicketGrantingTicketAction" />
		<transition to="serviceCheck" />
	</action-state>

	<decision-state id="serviceCheck">
		<if test="flowScope.service neq null" then="generateServiceTicket" else="viewGenericLoginSuccess" />
	</decision-state>
	
	<action-state id="generateServiceTicket">
        <evaluate expression="generateServiceTicketAction" />
		<transition on="success" to ="warn" />
		<transition on="error" to="generateLoginTicket" />
		<transition on="gateway" to="gatewayServicesManagementCheck" />
	</action-state>

    <action-state id="gatewayServicesManagementCheck">
        <evaluate expression="gatewayServicesManagementCheck" />
        <transition on="success" to="redirect" />
    </action-state>

    <action-state id="redirect">
        <evaluate expression="flowScope.service.getResponse(requestScope.serviceTicketId)" result-type="org.jasig.cas.authentication.principal.Response" result="requestScope.response" />
        <transition to="postRedirectDecision" />
    </action-state>

   
根据CAS登录的流程:

(1)验证TGT存在?true:在进入hasServiceCheck的时候增加了on-entry节点,该节点的功能是验证TGT是否expired,如果已经失效了,那么应该修改用户表里面的Token状态为未登录的状态(我们这里的用户表增加Token的功能主要是为了限制用户只能在一个地方登录。因此当用户已经在一个地方登录Token=1,退出或者关闭浏览器或者TGT失效的情况下回更改 Token = 0 )。

(2)第二个增加的流程是:当TGT存在的时候会进入验证reNew元素,如果renew ==null,说明不需要重新登录,那么这时候验证该URL是否在用户的关联列表里面,这个在数据库的User_Apps表里面会查询。如果存在就继续如果不存在,那么拒绝用户访问该应用。

(3)第三个需要更改的地方就是:当用户提交登录信息的时候,流程里面会有个Context和用户信息Credentials的绑定,这个时候还没有验证用户还没有生成TGT,然后我们在doBind和dorealSubmit之间增加URL的验证环节,考虑绑定之前还没有用户信息,所以不能增加验证,考虑提交之后会生成TGT这个时候再验证URL合法性,已经失去了意义,所以在中间这个环节增加节点,且不与原来的代码耦合,这样代码完全独立,只根据上下文获取信息。

上图为增加的几个主要的类,第一个UserLoginedOrNotAuthenticationHandler.Java类,部署在deploymengConfig.xml里面的authenticationHandler的<list>节点里面。

  1. <bean class="<span style="font-family:SimHei;">xxx</span>.<span style="font-family:SimHei;">xxx</span>.<span style="font-family:SimHei;">xxx</span>.auth.authentication.handler.support.UserLoginedOrNotAuthenticationHandler">  
  2.          <property name="queryDatabaseAuthenticationHandler" ref="queryDatabaseAuthenticationHandler"/>  
  3.          <property name="modifyLoginedStatusAttributeDAO" ref="modifyLoginedStatusAttributeDAO"/>  
  4.        </bean>  
 <bean class="xxx.xxx.xxx.auth.authentication.handler.support.UserLoginedOrNotAuthenticationHandler">
          <property name="queryDatabaseAuthenticationHandler" ref="queryDatabaseAuthenticationHandler"/>
          <property name="modifyLoginedStatusAttributeDAO" ref="modifyLoginedStatusAttributeDAO"/>
        </bean>
这里面引用了源码里面的QueryDatabaseAuthenticationHandler类的验证用户名和密码的功能,然后自己添加了第二个属性用于更改用户登录状态的类,这个类引用了jdbcTemplate,用户连接数据库。

第二个包里面是两个DAO层用于修改相应的数据库状态。分别是验证用户URL和修改登录Token的。里面的具体结构就不在这里详述了。

第三个包里面是重构源码中的LogoutController类,然后再配置文件中,class的值替换为该类。这里面实现了退出时修改用户的Token=0,其他与源码保持一致。

第四个主要是应用在login-webflow.xml里面,该类引用了上面两个DAO。

credentials属性为第一次登陆的之后记录credentials,此后沿用这个credentials。当用户重定向以后从request里面得不到用户信息,所以这里有必要保存

猜你喜欢

转载自blog.csdn.net/superiorpengFight/article/details/53536743
今日推荐