先補課,以下網址可以把CAS環境搭起來。
【JA-SIG CAS服務環境搭建】http://linliangyi2007.iteye.com/blog/165307
【JA-SIG CAS業務架構介紹】http://linliangyi2007.iteye.com/blog/165310
【JA-SIG CAS技術框架】http://linliangyi2007.iteye.com/blog/165313
【抓包分析】http://blog.csdn.net/clh604/article/details/20365967
【問題背景】兩個系統的整合就不說了,簡單來說就是網頁放在NginX上,但是ajax調用tomcat的API獲取數據,其中tomcat段用CAS做身份認證。具體使用的是org.jasig.cas.client,配置會略有不同就不展開了。
【問題描述】ajax調用不允許跨域訪問,如果在該容器中未CAS登陸(沒有ticket)則會遇到以下錯誤。
XMLHttpRequest cannot load [CAS服務器地址] No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin [應用地址] is therefore not allowed access.
【非ajax請求具體的跳轉請求】就是標准的跳轉,不上圖了:
請求1:http訪問tomcat。結果:302重定向指向CAS服務器
請求2:訪問CAS服務器,帶上CASTGC。結果:302重定向指向tomcat並帶上ticket
請求3:訪問tomcat,帶上ticket。結果:200返回資源
【ajax請求具體的跳轉請求】:
請求1:ajax訪問tomcat。結果:302重定向指向CAS服務器
請求2:訪問CAS服務器,帶上CASTGC。結果:200返回無內容,瀏覽器提示錯誤(chrome)
跨域訪問規則Access-Control-Allow-Origin是在CAS服務器配置的,項目無法更改。
【參考的解決方法】
a.在session超時的情況下發ajax請求。返回200正常,並在json中指定狀態碼302和login.action地址
b.訪問login.action。302重定向指向CAS服務器
c.訪問CAS服務器登錄授權。302重定向回login.action
d.訪問login.action帶有ticket。302重定向next_page(即一開始ajax請求的頁)
e.訪問next_page刷新整個頁
【具體解決過程】
1.修改CAS授權過濾器,session無效的ajax請求先返回200正常,並在json中指定業務錯誤碼session_lost
繼承修改AuthenticationFilter的doFilter方法:
a.如果session中有assertion,通過,進入下一層(tomcat端向CAS服務器驗證ticket)
b.(無assertion)如果有ticket,通過,進入下一層filter(tomcat端向CAS服務器驗證ticket)
c.(無assertion無ticket)普通http請求,重定向到CAS服務器
d.(無assertion無ticket)ajax請求,返回200並在json中指定session_lost
e.改配置web.xml,指向新的AuthenticationFilter類,並且serverName要與NginX的域名匹配
2.在js的callback中處理session_lost,將網址定位到/login.action
window.location.href=/app/login.action
3.在java的/autoLogin中重新登錄並根據參數next_page重定向,完成登錄和刷新
(因為是普通http請求,會先跳轉到CAS登錄,回來建立session信息,然后再跳轉到用戶本來的頁面)
【其中一些細節問題】
a.通過檢查請求頭的"X-Requested-With"為"XMLHttpRequest"鑒別是ajax調用
b./login.action中要判斷nextpage避免指向自己,若"/login.action?nextpage=/login.action"會導致死循環,爆棧很歡樂~
c.登錄后cookies對JSESSIONID寫入不對也會導致session找不到而死循環,一番排查后發現Tomcat寫入的cookies匹配的path是應用路徑,而網頁上匹配的是根路徑,所以需要手動寫cookies把JSESSIONID匹配path為"/"。
d.web.xml中serverName要與網頁域名匹配(因為這里經過了DNS和反向代理),否則會報登錄的service與當前訪問的service(即域名)不匹配的錯誤。
e.幾種跳轉方式的區分
request.getRequestDispatcher(str).forward(request, response);
---服務器內部跳轉,路徑從應用開始算,即"/"等效於 "http://域名/應用/"
response.sendRedirect(str);
---瀏覽器端302重定向,參數為完整地址。
@Controller實例的方法中的return str;
---服務器內部加載頁面,路徑從應用開始算。
@Controller實例的方法中的return "redirect:/";
---瀏覽器端302重定向,但是路徑從應用開始算。
瀏覽器端js中window.location.href
---瀏覽器本窗口打開頁面,路徑從域名后開始計算,即"/"等效於 "http://域名/"
f.warnning:第一個是CSRF風險即cookies被盜用,電腦入域或網絡隔離可規避;第二個是serverName配置是寫死在web.xml上,改域名就要重新部署應用,可改為配置。
完事,可以ajax隨便愉快玩耍了~