自定義Token的CAS登錄


工作中實際遇到的需求,我們有一個舊系統,用了CAS的單點登錄,現在有一個外部系統,准備從它那里單點進來,這個外部系統提供了一個token參數來標記這是哪一個用戶,我們用他們提供的方式解析出對應的用戶,以這個用戶從CAS登錄進系統。

有關CAS登錄的分析網上多如牛毛,這里不准備多作分析了,直接上解決過程。

這里實現是基於我們以前系統的,是CAS 3.5.2
  • 首先在登錄流程文件login-webflow.xml里在on-start節點后面插入
<decision-state id="tokenCheck">
   <if test="requestParameters.token != null and requestParameters.token != ''" then="tokenValidate" else="ticketGrantingTicketExistsCheck" />
</decision-state>

在這里檢查是否有token參數,有的話執行token驗證,沒有的話走正常流程,ticketGrantingTicketExistsCheck就是原有的正常流程。

 

  • 定義token驗證節點
<action-state id="tokenValidate">
   <evaluate expression="tokenLoginAction.doExecute(flowRequestContext)" />
   <transition on="error" to="generateLoginTicket" />
   <transition on="success" to="sendTicketGrantingTicket" />
</action-state>

失敗則走generateLoginTicket分支,會生成一個LT,並重定向到登錄頁面,這也是通常頁面登錄失敗后的路徑

成功則走sendTicketGrantingTicket分支,即頁面正常登錄成功時走的路徑

 
  • 實現token驗證流程節點

在cas-servlet.xml里添加添加tokenLoginAction Bean

<bean id="tokenLoginAction" class="org.jasig.cas.web.flow.TokenLoginAction"
    p:centralAuthenticationService-ref="centralAuthenticationService" />

實現TokenLoginAction

這里主要解析token,並生成TGT。主要代碼如下:

HttpServletRequest request = WebUtils.getHttpServletRequest(context);
String token = request.getParameter("token");

 try {

  //解析Token,略。。。。。。

   CasCredentials credentials = new CasCredentials();
   credentials.setUsername(userName);
   credentials.setPassword("");
   credentials.setNoAuth(true);
  
   String tgt = centralAuthenticationService.createTicketGrantingTicket(credentials);
   WebUtils.putTicketGrantingTicketInRequestScope(context,tgt);
  
 } catch (Exception e) {
   e.printStackTrace();
  return "error";
 }
 
 return "success";
TokenLoginAction的主要邏輯代碼

上面centralAuthenticationService是注入的屬性,

CasCredentials則是繼承自UsernamePasswordCredentials的一個自定義Credentials,在用戶名、密碼基礎上添加了一個noAuth屬性,用來標記是不是需要驗證密碼。這里由外系統提供的token保證安全性,把noAuth設為true。

而登錄驗證邏輯在createTicketGrantingTicket這個方法里,驗證未通過會拋出異常。

真正驗證的地方則是在authenticationManager里,里面有authenticationHandlers定義了驗證方法
  • 修改登錄驗證邏輯

login-webflow.xml頂部把credentials的定義先改了

<var name="credentials" class="com.cas.util.CasCredentials" />

deployerConfigContext.xml找到自定義登錄驗證所在

<bean id="authenticationManager" class="">
   <property name="authenticationHandlers">
  <list>
                           <bean
    class="com.cas.util.QueryUserAuthenticationHandler">
......
                           </bean>
                       </list>
   </property>
</bean>

 

在這個QueryUserAuthenticationHandler class里,驗證密碼之前加入

  if (CasCredentials.class.isInstance(credentials)) {
   if (((CasCredentials)credentials).isNoAuth())
    return true;
  }

 

這樣就完成了傳入第三方token的CAS登錄。

似乎是完成了,但其實還有一些東西,

比如第三方進來的時候是不用他們傳Service這個參數的,而這個參數是在CAS登錄初始化時處理掉的,后面沒有地方自己往request里加這個參數讓CAS來處理它,自己寫requestscope里寫Service對象又很麻煩,看了下代碼,得注入很多東西才行。這樣就在進入CAS流程前,自己往請求里塞一個Service參數,然后重定向到CAS登錄的url。

再比如,這次是別人提供Token用他們的方法解;以后有需求是我們提供一個Token出去,接收進來后用我們的方法自己解。所以其實TokenLoginAction那里解析Token其實是解本方提供出去的Token。解別人的Token呢前置到塞Service參數那個地方,那里解析出來用戶名后,再用自己的方法生成一個Token發給CAS。這樣就把第三方的Token解析分離出去了,CAS登錄的地方不會跟別人的實現綁在一起。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM