前後端星散下的CAS跨域流程剖析

寫在最前

前後端星散實在有兩類:

  1. 開闢階段運用dev-server,臨盆階段是打包成靜態文件全部放入後端項目中。
  2. 開闢階段運用dev-server,臨盆階段是打包成靜態文件放入零丁的靜態資本效勞器中,如nginx。

這兩種計劃最大的區分就是臨盆階段。由於第一種計劃前端和後端實質在同一個效勞中的,所以壓根就沒有跨域,設置cas的坑比較少。而第二種計劃我們平常運用nginx反向代辦完成跨域,設置cas的坑會許多。為了背面剖析輕易,我們分別稱上述兩種計劃為『前後端星散A』和『前後端星散B』

要求也分為兩類:

1.HTTP要求:像瀏覽器地點欄提議的要求、瀏覽器自覺的接見某個網址、Postman測試接口,這些行動實在都是提議的HTTP要求,不會有跨域題目。

2.AJAX(XMLHttpRequest)要求:這是瀏覽器內部的XMLHttpRequest對象提議的要求,瀏覽器會制止其提議跨域的要求,重要是為了防備跨站劇本捏造的進擊(CSRF)。

難點剖析

前後端星散、跨域、CAS這三項手藝零丁運用起來,以至拿个中兩個出來一同運用,難度都不大,下面來枚舉一下:

  1. 前後端星散(AB)+跨域
  2. 前後端星散A+CAS(由於A計劃基礎就沒有跨域這一說)
  3. 前後端星散B+跨域+CAS

前後端星散(AB)+跨域

這個最簡樸,只要跨域,沒有CAS,罕見的CORS、反向代辦、JSONP都能夠處置懲罰

前後端星散A+CAS

坑:CAS認證逾期,莫名湧現跨域毛病的題目

能夠有人會問,適才不是說計劃A壓根就沒有跨域題目嗎?實在,這個跨域毛病不怪我們的後端,而是怪CAS那裡的後端,待我細緻說來。

一般狀況下,CAS認證勝利后,瀏覽器會設置好一個來自CAS的Cookie以堅持與CAS的Session。以後每次要求,無論是ajax要求照樣http要求,都邑帶上這個cookie。而我們本身的後端效勞器也會有一個CAS Authorization的過濾器,把沒有CAS認證過的要求重定向到CAS的login頁面。由於本次要求我們帶了cas的cookie,所以要求順遂經由過程filter來到controller層,進而返回數據。

然則斟酌如許一個狀況,本日你翻開你的瀏覽器,接見一個你們新做的cms體系的網址,然後跳到cas login頁面,一般上岸,一般運用。然後來到第二天早上,由於昨天的頁面你沒關,你直接點了一個查詢按鈕,效果報錯了。你翻開瀏覽器控制台,居然發明報了一個跨域的毛病。這裡有兩處疑心:

  1. 為何他喵的會跨域呢?我們前後端定名布置在一台效勞器上,是同域的啊。
  2. 為何cas認證失效后,沒有自動跳到cas登錄頁呢?但是我之前直接在瀏覽器輸入cms體系的地點時,由於沒認證過,瀏覽器是能直接跳到cas登錄頁的,為何此次不可呢?
  3. ajax究竟怎樣處置懲罰302的

為何會跨域:
想一想一下如許的一個流程:第二天早上你來,點擊一個查詢按鈕,提議了ajax要求,要求中帶上了一個已失效的cookie,然後要求被後端cas filter阻攔,發明已失效,讓后302跳轉到cas login界面。在這個過程當中,你之前提議的ajax要求實在被redirect到了cas的login.html頁面(這隻是表象,實質背面會提到)。你相當於提議ajax要求去要求一個html文件下來,但是cas的效勞器並沒有設置跨域,為了平安斟酌也不能設置跨域,所以你的ajax要求還沒來得及要求下來數據,你就被瀏覽器認為是跨域了,由於你確實在要求cas效勞器的一個靜態資本。

退一萬步說,就算cas效勞器設置了跨域,雖然你點擊查詢按鈕的行動不會報跨域毛病了,但你依舊不能自動跳轉到cas login頁面,由於這個login.html直接當作你ajax的success中的回調參數回來了,瀏覽器是不會幫你跳轉的。

為何不能跳轉:
起首,你翻開瀏覽器輸入cms體系的地點去接見的時刻,提議的是HTTP要求,是不存在跨域題目的。因而你的HTTP要求被後端的filter給redirect到了cas的login.html,這個流程是沒題目的。而你點擊查詢按鈕,提議的是ajax要求,是沒法跳轉的(詳細緣由見下方筆墨)

ajax在302中的行動實質
當你點擊查詢按鈕,提議的是ajax要求,要求被後端filter阻攔,並示知你302跳轉到login頁,此時瀏覽器起首會感知到此次ajax要求的302狀況,並替ajax去接見要跳轉到的地點,然後將接見的效果(實在就是全部login.html頁面)返回到你的ajax的success回調函數中,因而這個回調函數的參數實在就是全部login.html的頁面。而且,直到瀏覽器把html放到ajax的success回調函數后,ajax才會真正的回調,之前的302狀況ajax是感知不到的,固然也獵取不到,所以想經由過程ajax推斷status是不是是302,進而手動location.href到login頁的計劃是不可的。

實在,這麼看起來就像是你的ajax直接要求到了login.html頁面。
別的,在現實cas跳轉的過程當中,在ajax的success回調之前,你的ajax操縱就被瀏覽器認為是跨域了,所以你壓根就沒時機回調success,也因而獵取不到status狀況或許誰人沒卵用的login.html。

好了,迷惑處置懲罰完了,該說說處置懲罰計劃了:

我們要完成的就是:在cookie失效時,點擊查詢按鈕后,能自動跳轉到cas登錄頁。
計劃許多,但都靠一下兩點:
用HTTP要求替換Ajax要求去跳轉到登錄頁
用200替代302示知ajax當前要求的狀況

舉幾個例子:

1、毛病計劃:想法阻攔ajax的response,然後推斷response的status是不是是302,假如是302就手動location.href跳到cas登錄頁,然則如許是不可的,由於我們基礎獵取不到這個302狀況。
2、必須要後端合營,後端須要分外加1個filter和1個controller, 起個名字吧,就叫ValidateFilter和ValidateController吧。

ValidateFilter只過濾那些須要被cas阻攔的要求,在doFilter內里推斷HttpServletRequest的狀況,看看這個request里能不能獵取到當前用戶名,假如能獵取到,代表認證沒題目,讓這個要求繼承往下走chain.doFilter,假如不能獵取到,代表認證失效了(由於filter不能直接返回,所以我們須要一個ValidateController),我們request.dispatch這個要求到ValidateController的redirect要領中(本身寫的),讓這個redirect要領返回一個result,result中設置一個標誌,比方給code:xxx。

然後前端想法在ajax的response之前獵取response的result,看看result的code是不是為xxx,假如是,那就location.href跳轉到cas登錄頁即可,个中service參數寫cas上岸以後要回調的後端接口,然後讓後端去跳轉到前端頁面。

為何不能直接service寫前端?
由於我們不僅要跟cas效勞器堅持session,還要跟我們本身的後端堅持session,假如不回調後端,後端就不會感知到我們的登錄狀況了。

比方:

//前端:
if(result.code === xxx) {
    location.href = "http://cas.server.com/login?service=http://後端效勞器地點/redirect/to/frontend?currentPath=當前頁面途徑"
    //currentPath是為了login以後再調回當前頁面
}
//後端 filter 偽代碼:
void doFilter(request, response, chain) {

    if(request中有用戶名) {
      chain.doFilter()
    } else if(request.uri == '/redirect/to/caslogin') {
      chain.doFilter()
    } else {
        request.dispatch("/redirect/to/caslogin")
    }
}
//後端 controller 偽代碼
// 用來接收filter過來的那些認證失效的要求
@path("/redirect/to/caslogin")
String redirectToCasLogin(request, response) {
    return {
        "code": xxx
    }
}
// 用來在login以後回挪用
@path("/redirect/to/frontend")
String redirectToFrontend(request, response) {
  String path = request中的currentPath參數
  request.sendRedirect(path)
}

// 別的,這個controller肯定不要被validateFilter過濾,由於假如這個controller也要被過濾,那就墮入cas考證的死循環了。

3.和2相似,然則location.href中直接寫

location.href = "http://後端效勞器地點/redirect/to/caslogin?currentPath=當前頁面途徑"

此時我們直接要求後端接口/redirect/to/caslogin,他起首被validateFilter阻攔,然則由於有一個if推斷,他被直接doFilter,然後要求來到了cas的Filter,由於沒登錄,該filter會自動拼接我們設置的cas serverName+當前要求的uri,同樣會構成
“http://cas.server.com/login?service=http://後端效勞器地點/redirec…徑”如許的url。

前後端星散B+跨域+CAS

寫不動了,總之要注意:要堅持cookie的域一致

關於nginx,假如從 www.a.com/ 代辦到 www.b.com/api,那末構成的cookie的域是會是/api,而瀏覽器提議要求時只能照顧/域的cookie,所以致使cookie喪失,session失效。能夠經由過程nginx設置,把/api域下的cookie都放到/即可處置懲罰。
為了防止分外的貧苦,最好堅持代辦前後url一致吧,即都有一個/api前綴,或許都沒有。

關於瀏覽器,提議的ajax所帶的cookie是提議要求的host域名有嚴厲關聯的,差別的域名帶差別的cookie,所以假如湧現,你明顯已上岸了,然則在此提議ajax要求,後端照樣辨認不出來你的登錄狀況,那就多是你提議的要求的域名不一致了。也就是說,你去要求後端接口的時刻用www.a.com,效果cas上岸勝利后的要回調的接口成了www.b.com,如許你的cas登錄狀況的cookie就附着在www.b.com的域名上了,然後當你再提議www.a.com的要求的時刻,發明你基礎帶不上cas下來的cookie,由於域差別。
這類狀況一般發生在反向代辦的時刻,前端提議ajax要求代辦效勞器www.a.com,代辦效勞器提議要求到www.b.com,這時刻就輕易致使域名不一致,請肯定要注意這點。

別的,關於當前前後端離開布置的狀況,location.href中,service的回調接口不能直接寫後端地點(相當於www.b.com),而應當寫www.a.com,讓代辦效勞器去接見www.b.com,如許才堅持cookie的域的一致性!!!!

    原文作者:fxxjdedd
    原文地址: https://segmentfault.com/a/1190000015235402
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞