先補課,如下網址能夠把CAS環境搭起來。java
【JA-SIG CAS服務環境搭建】http://linliangyi2007.iteye.com/blog/165307web
【JA-SIG CAS業務架構介紹】http://linliangyi2007.iteye.com/blog/165310ajax
【JA-SIG CAS技術框架】http://linliangyi2007.iteye.com/blog/165313chrome
【抓包分析】http://blog.csdn.net/clh604/article/details/20365967json
【問題背景】兩個系統的整合就不說了,簡單來講就是網頁放在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.tomcat
【非ajax請求具體的跳轉請求】就是標準的跳轉,不上圖了:服務器
請求1:http訪問tomcat。結果:302重定向指向CAS服務器cookie
請求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隨便愉快玩耍了~