成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

前后端分離下的CAS跨域流程分析

ckllj / 2631人閱讀

摘要:這種情況通常發(fā)生在反向代理的時候,前端發(fā)起請求代理服務(wù)器,代理服務(wù)器發(fā)起請求到,這時候就容易導(dǎo)致域名不一致,請一定要注意這點(diǎn)。

寫在最前 前后端分離其實(shí)有兩類:

開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件整個放入后端項(xiàng)目中。

開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件放入多帶帶的靜態(tài)資源服務(wù)器中,如nginx。

這兩種方案最大的區(qū)別就是生產(chǎn)階段。由于第一種方案前端和后端本質(zhì)在同一個服務(wù)中的,所以壓根就沒有跨域,配置cas的坑比較少。而第二種方案我們一般使用nginx反向代理完成跨域,配置cas的坑會很多。為了后面分析方便,我們分別稱上述兩種方案為『前后端分離A』和『前后端分離B』

請求也分為兩類:

1.HTTP請求:像瀏覽器地址欄發(fā)起的請求、瀏覽器自發(fā)的訪問某個網(wǎng)址、Postman測試接口,這些行為其實(shí)都是發(fā)起的HTTP請求,不會有跨域問題。

2.AJAX(XMLHttpRequest)請求:這是瀏覽器內(nèi)部的XMLHttpRequest對象發(fā)起的請求,瀏覽器會禁止其發(fā)起跨域的請求,主要是為了防止跨站腳本偽造的攻擊(CSRF)。

難點(diǎn)分析

前后端分離、跨域、CAS這三項(xiàng)技術(shù)多帶帶使用起來,甚至拿其中兩個出來一起使用,難度都不大,下面來列舉一下:

前后端分離(AB)+跨域

前后端分離A+CAS(因?yàn)锳方案根本就沒有跨域這一說)

前后端分離B+跨域+CAS

前后端分離(AB)+跨域

這個最簡單,只有跨域,沒有CAS,常見的CORS、反向代理、JSONP都可以解決

前后端分離A+CAS 坑:CAS認(rèn)證過期,莫名出現(xiàn)跨域錯誤的問題

可能有人會問,剛才不是說方案A壓根就沒有跨域問題嗎?其實(shí),這個跨域錯誤不怪我們的后端,而是怪CAS那邊的后端,待我詳細(xì)說來。

正常情況下,CAS認(rèn)證成功后,瀏覽器會設(shè)置好一個來自CAS的Cookie以維持與CAS的Session。之后每次請求,無論是ajax請求還是http請求,都會帶上這個cookie。而我們自己的后端服務(wù)器也會有一個CAS Authorization的過濾器,把沒有CAS認(rèn)證過的請求重定向到CAS的login頁面。因?yàn)楸敬握埱笪覀儙Я薱as的cookie,所以請求順利通過filter來到controller層,進(jìn)而返回?cái)?shù)據(jù)。

但是考慮這樣一個情況,今天你打開你的瀏覽器,訪問一個你們新做的cms系統(tǒng)的網(wǎng)址,然后跳到cas login頁面,正常登陸,正常使用。然后來到第二天早上,因?yàn)樽蛱斓捻撁婺銢]關(guān),你直接點(diǎn)了一個查詢按鈕,結(jié)果報錯了。你打開瀏覽器控制臺,竟然發(fā)現(xiàn)報了一個跨域的錯誤。這里有兩處困惑:

為什么他喵的會跨域呢?我們前后端命名部署在一臺服務(wù)器上,是同域的啊。

為什么cas認(rèn)證失效后,沒有自動跳到cas登錄頁呢?可是我之前直接在瀏覽器輸入cms系統(tǒng)的地址時,因?yàn)闆]認(rèn)證過,瀏覽器是能直接跳到cas登錄頁的,為什么這次不行呢?

ajax到底怎么處理302的

為什么會跨域:
想想一下這樣的一個流程:第二天早上你來,點(diǎn)擊一個查詢按鈕,發(fā)起了ajax請求,請求中帶上了一個已經(jīng)失效的cookie,然后請求被后端cas filter攔截,發(fā)現(xiàn)已失效,讓后302跳轉(zhuǎn)到cas login界面。在這個過程中,你之前發(fā)起的ajax請求其實(shí)被redirect到了cas的login.html頁面(這只是表象,本質(zhì)后面會提到)。你相當(dāng)于發(fā)起ajax請求去請求一個html文件下來,然而cas的服務(wù)器并沒有配置跨域,為了安全考慮也不能配置跨域,所以你的ajax請求還沒來得及請求下來數(shù)據(jù),你就被瀏覽器認(rèn)為是跨域了,因?yàn)槟愕拇_在請求cas服務(wù)器的一個靜態(tài)資源。

退一萬步說,就算cas服務(wù)器配置了跨域,雖然你點(diǎn)擊查詢按鈕的行為不會報跨域錯誤了,但你依然不能自動跳轉(zhuǎn)到cas login頁面,因?yàn)檫@個login.html直接當(dāng)做你ajax的success中的回調(diào)參數(shù)回來了,瀏覽器是不會幫你跳轉(zhuǎn)的。

為什么不能跳轉(zhuǎn):
首先,你打開瀏覽器輸入cms系統(tǒng)的地址去訪問的時候,發(fā)起的是HTTP請求,是不存在跨域問題的。因此你的HTTP請求被后端的filter給redirect到了cas的login.html,這個流程是沒問題的。而你點(diǎn)擊查詢按鈕,發(fā)起的是ajax請求,是沒法跳轉(zhuǎn)的(具體原因見下方文字)

ajax在302中的行為本質(zhì)
當(dāng)你點(diǎn)擊查詢按鈕,發(fā)起的是ajax請求,請求被后端filter攔截,并告知你302跳轉(zhuǎn)到login頁,此時瀏覽器首先會感知到這次ajax請求的302狀態(tài),并替ajax去訪問要跳轉(zhuǎn)到的地址,然后將訪問的結(jié)果(其實(shí)就是整個login.html頁面)返回到你的ajax的success回調(diào)函數(shù)中,因此這個回調(diào)函數(shù)的參數(shù)其實(shí)就是整個login.html的頁面。并且,直到瀏覽器把html放到ajax的success回調(diào)函數(shù)后,ajax才會真正的回調(diào),之前的302狀態(tài)ajax是感知不到的,當(dāng)然也獲取不到,所以想通過ajax判斷status是否是302,進(jìn)而手動location.href到login頁的方案是不行的。

其實(shí),這么看起來就像是你的ajax直接請求到了login.html頁面。
另外,在實(shí)際cas跳轉(zhuǎn)的過程中,在ajax的success回調(diào)之前,你的ajax操作就被瀏覽器認(rèn)為是跨域了,所以你壓根就沒機(jī)會回調(diào)success,也因此獲取不到status狀態(tài)或者那個沒卵用的login.html。

好了,疑惑解決完了,該說說解決方案了:

我們要實(shí)現(xiàn)的就是:在cookie失效時,點(diǎn)擊查詢按鈕后,能自動跳轉(zhuǎn)到cas登錄頁。
方案很多,但都靠一下兩點(diǎn):
用HTTP請求替代Ajax請求去跳轉(zhuǎn)到登錄頁
用200代替302告知ajax當(dāng)前請求的狀態(tài)

舉幾個例子:

1、錯誤方案:設(shè)法攔截ajax的response,然后判斷response的status是否是302,如果是302就手動location.href跳到cas登錄頁,但是這樣是不行的,因?yàn)槲覀兏精@取不到這個302狀態(tài)。
2、必須要后端配合,后端需要額外加1個filter和1個controller, 起個名字吧,就叫ValidateFilter和ValidateController吧。

ValidateFilter只過濾那些需要被cas攔截的請求,在doFilter里面判斷HttpServletRequest的狀態(tài),看看這個request里能不能獲取到當(dāng)前用戶名,如果能獲取到,代表認(rèn)證沒問題,讓這個請求繼續(xù)往下走chain.doFilter,如果不能獲取到,代表認(rèn)證失效了(因?yàn)閒ilter不能直接返回,所以我們需要一個ValidateController),我們request.dispatch這個請求到ValidateController的redirect方法中(自己寫的),讓這個redirect方法返回一個result,result中設(shè)置一個標(biāo)志,比如給code:xxx。

然后前端設(shè)法在ajax的response之前獲取response的result,看看result的code是否為xxx,如果是,那就location.href跳轉(zhuǎn)到cas登錄頁即可,其中service參數(shù)寫cas登陸之后要回調(diào)的后端接口,然后讓后端去跳轉(zhuǎn)到前端頁面。

為什么不能直接service寫前端?
因?yàn)槲覀儾粌H要跟cas服務(wù)器維持session,還要跟我們自己的后端維持session,如果不回調(diào)后端,后端就不會感知到我們的登錄狀態(tài)了。

比如:

//前端:
if(result.code === xxx) {
    location.
    //currentPath是為了login之后再調(diào)回當(dāng)前頁面
}
//后端 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過來的那些認(rèn)證失效的請求
@path("/redirect/to/caslogin")
String redirectToCasLogin(request, response) {
    return {
        "code": xxx
    }
}
// 用來在login之后回調(diào)用
@path("/redirect/to/frontend")
String redirectToFrontend(request, response) {
  String path = request中的currentPath參數(shù)
  request.sendRedirect(path)
}

// 另外,這個controller一定不要被validateFilter過濾,因?yàn)槿绻@個controller也要被過濾,那就陷入cas驗(yàn)證的死循環(huán)了。

3.和2類似,但是location.href中直接寫

location.href = "http://后端服務(wù)器地址/redirect/to/caslogin?currentPath=當(dāng)前頁面路徑"

此時我們直接請求后端接口/redirect/to/caslogin,他首先被validateFilter攔截,但是因?yàn)橛幸粋€if判斷,他被直接doFilter,然后請求來到了cas的Filter,因?yàn)闆]登錄,該filter會自動拼接我們配置的cas serverName+當(dāng)前請求的uri,同樣會形成
"http://cas.server.com/login?service=http://后端服務(wù)器地址/redirec...徑"這樣的url。

前后端分離B+跨域+CAS

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

對于nginx,如果從 www.a.com/ 代理到 www.b.com/api,那么形成的cookie的域是會是/api,而瀏覽器發(fā)起請求時只能攜帶/域的cookie,所以導(dǎo)致cookie丟失,session失效??梢酝ㄟ^nginx配置,把/api域下的cookie都放到/即可解決。
為了避免額外的麻煩,最好保持代理前后url一致吧,即都有一個/api前綴,或者都沒有。

對于瀏覽器,發(fā)起的ajax所帶的cookie是發(fā)起請求的host域名有嚴(yán)格關(guān)系的,不同的域名帶不同的cookie,所以如果出現(xiàn),你明明已經(jīng)登陸了,但是在此發(fā)起ajax請求,后端還是識別不出來你的登錄狀態(tài),那就可能是你發(fā)起的請求的域名不一致了。也就是說,你去請求后端接口的時候用www.a.com,結(jié)果cas登陸成功后的要回調(diào)的接口成了www.b.com,這樣你的cas登錄狀態(tài)的cookie就附著在www.b.com的域名上了,然后當(dāng)你再發(fā)起www.a.com的請求的時候,發(fā)現(xiàn)你根本帶不上cas下來的cookie,因?yàn)橛虿煌?br>這種情況通常發(fā)生在反向代理的時候,前端發(fā)起ajax請求代理服務(wù)器www.a.com,代理服務(wù)器發(fā)起請求到www.b.com,這時候就容易導(dǎo)致域名不一致,請一定要注意這點(diǎn)。

另外,對于當(dāng)前前后端分開部署的情況,location.href中,service的回調(diào)接口不能直接寫后端地址(相當(dāng)于www.b.com),而應(yīng)該寫www.a.com,讓代理服務(wù)器去訪問www.b.com,這樣才能保持cookie的域的一致性?。。?!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/108074.html

相關(guān)文章

  • 前后分離下的CAS跨域流程分析

    摘要:這種情況通常發(fā)生在反向代理的時候,前端發(fā)起請求代理服務(wù)器,代理服務(wù)器發(fā)起請求到,這時候就容易導(dǎo)致域名不一致,請一定要注意這點(diǎn)。 寫在最前 前后端分離其實(shí)有兩類: 開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件整個放入后端項(xiàng)目中。 開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件放入單獨(dú)的靜態(tài)資源服務(wù)器中,如nginx。 這兩種方案最大的區(qū)別就是生產(chǎn)階段。由于第...

    DevTalking 評論0 收藏0
  • 前后分離下的CAS跨域流程分析

    摘要:這種情況通常發(fā)生在反向代理的時候,前端發(fā)起請求代理服務(wù)器,代理服務(wù)器發(fā)起請求到,這時候就容易導(dǎo)致域名不一致,請一定要注意這點(diǎn)。 寫在最前 前后端分離其實(shí)有兩類: 開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件整個放入后端項(xiàng)目中。 開發(fā)階段使用dev-server,生產(chǎn)階段是打包成靜態(tài)文件放入單獨(dú)的靜態(tài)資源服務(wù)器中,如nginx。 這兩種方案最大的區(qū)別就是生產(chǎn)階段。由于第...

    jay_tian 評論0 收藏0
  • 前后分離下的跨域CAS請求

    摘要:最重要的兩點(diǎn)請求跨域的時候,默認(rèn)不會攜帶。通常是這樣的前端發(fā)起,后端接受請求并執(zhí)行,前端接受相應(yīng)并發(fā)起,請求重定向后的頁面,其中不存在跨域問題。 最重要的兩點(diǎn): ajax請求跨域的時候,默認(rèn)不會攜帶cookie。 請求分為普通請求(HttpRequest)和Ajax請求(XMLHttpRequest) 先屢一下跨域CAS認(rèn)證的流程: 前端發(fā)起ajax請求,請求首先被跨域Filter...

    Tony_Zby 評論0 收藏0
  • 前后分離下的跨域CAS請求

    摘要:最重要的兩點(diǎn)請求跨域的時候,默認(rèn)不會攜帶。通常是這樣的前端發(fā)起,后端接受請求并執(zhí)行,前端接受相應(yīng)并發(fā)起,請求重定向后的頁面,其中不存在跨域問題。 最重要的兩點(diǎn): ajax請求跨域的時候,默認(rèn)不會攜帶cookie。 請求分為普通請求(HttpRequest)和Ajax請求(XMLHttpRequest) 先屢一下跨域CAS認(rèn)證的流程: 前端發(fā)起ajax請求,請求首先被跨域Filter...

    CoffeX 評論0 收藏0
  • 使用 vue2.0 開發(fā)微信公眾號下前后分離的SPA站點(diǎn)的填坑之旅

    摘要:目前正在寫一個微信公眾號的小項(xiàng)目,記錄一下遇到的問題和解決方法主要是前端。前端提交時使用,在后端再取出對應(yīng)的微信支付看了下文檔,以前是需要用喚起支付,而現(xiàn)在則是把微信內(nèi)置到了微信的瀏覽器中。 目前正在寫一個微信公眾號的小項(xiàng)目,記錄一下遇到的問題和解決方法(主要是前端)。內(nèi)容持續(xù)更新中~ 主要實(shí)現(xiàn) 前后端分離前端為 SPA 單頁面使用微信的JSSDK微信支付 技術(shù)方案 后端使用 php ...

    afishhhhh 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<