如何在跨域請求中允許帶入原網站的cookie(401:not authorizated)

博主在項目開發中,遇到一個問題,在當前網頁,發送一個跨域請求,可是瀏覽器給我報401:not authorizated。一開始以爲是我寫的http請求沒有帶入一些身份驗證信息,後來仔細研究了下,此跨域請求沒有帶包含認證信息的cookie,可是我看了項目中別的http請求壓根沒有單獨去設置這種cookie。
我又看了下Chrome—》 DevTools—》application—》Cookies,發現包含認證信息的cookie已經全部在當前域下了。說明我在發送請求時,並不需要自己在重新設置cookie值了;既然已經有cookie值,爲什麼我發送的請求的Request Headers裏沒有自動帶上已經存在的cookie呢?
所以我在懷疑是不是因爲我發送的請求時跨域的呢?
帶着這個懷疑,我着重看了下CORS跨域相關文檔。

一. CORS

Cross-Origin Resource Sharing 是 W3C 推出的一種跨站資源獲取的機制。

首先我們來看一下瀏覽器的支持情況:


ChromeFirefox (Gecko)Internet ExplorerOperaSafari
43.58 & 9(XDomainRequest), 10124

移動端的瀏覽器對這種方法的支持比較完善。
現在我們看到了,如果不需要兼容 IE6、7的話,就可以使用這種方法。

這種跨域方案主要的思想是:服務器 在響應頭中設置相應的選項,瀏覽器如果支持這種方法的話就會將這種跨站資源請求視爲合法,進而獲取資源。

1.服務端可以設置的響應頭信息:

  • (1) Access-Control-Allow-Origin
    Access-Control-Allow-Origin: <origin> | *

    origin: 被允許跨域訪問這個資源的網站,* 代表全部網站。瀏覽器會檢測這個參數,如果符合要求,纔會去獲取資源。
    舉個例子,允許 http://jasonkid.github.io/fezone 來跨域訪問這個資源:
    Access-Control-Allow-Origin: http://jasonkid.github.io/fezone

  • (2) Access-Control-Allow-Credentials
    Access-Control-Allow-Credentials: true | false
    表示是否允許瀏覽器攜帶 Cookie 來訪問這個資源。
    這個屬性要和 XMLHttpRequest 的 withCredentials 屬性來配合使用。

    var xhr = new XMLHttpRequest();
    var url = 'http://foo.other/resources/credentialed-content/';
    
    if(xhr) {
        xhr.open('GET', url, true);
        xhr.withCredentials = true; // 設置帶有 Cookie 的資源請求
        xhr.onreadystatechange = handler;
        xhr.send(); 
    }
    
  • (1) XMLHttpRequest 對象中指定了 withCredentials = true

  • (2) 服務器響應頭中 Access-Control-Allow-Credentials: true

  • (3) 服務器響應頭中 Access-Control-Allow-Origin 不能爲 *

以下選項主要是安全性配置的問題,主要是服務器的配置問題了,就不展開介紹了:

Access-Control-Expose-Headers

Access-Control-Allow-Methods

Access-Control-Allow-Headers

所以,在發送跨域請求時之所以沒能帶上cookie,很有可能是因爲ajax沒有設置`withCredentials = true`這一屬性。
那麼繼續研究下withCredentials屬性是幹啥吃的。。

二.withCredentials

查閱MSDN《火狐開發者文檔》,發現有詳細介紹:

XMLHttpRequest.withCredentials  屬性是一個Boolean類型,它指示了是否該使用類似cookies,authorization headers(頭部授權)或者TLS客戶端證書這一類資格證書來創建一個跨站點訪問控制(cross-site Access-Control)請求。在同一個站點下使用withCredentials屬性是無效的。

此外,這個指示也會被用做響應中cookies 被忽視的標示。默認值是false。

如果在發送來自其他域的XMLHttpRequest請求之前,未設置withCredentials 爲true,那麼就不能爲它自己的域設置cookie值。而通過設置withCredentials 爲true獲得的第三方cookies,將會依舊享受同源策略,因此不能被通過document.cookie或者從頭部相應請求的腳本等訪問。

注: 永遠不會影響到同源請求

Note: 不同域下的XmlHttpRequest 相應,不論其Access-Control- header 設置什麼值,都無法爲它自身站點設置cookie值,除非它在請求之前將withCredentials 設爲true。

實例
<code>
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://example.com/', true);
    xhr.withCredentials = true;
    xhr.send(null);
</code>

詳見:
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/withCredentials

到此,已經很明白了,解決上述的問題就是需要設置xhr.withCredentials = true這一項。
但是,我是使用JQuery封裝的ajax,所以需要藉助$.ajax()方法的
xhrFields屬性。(xhrFields是一個具有多個”字段名稱-字段值”對的對象,用於對本地XHR對象進行設置。)

    jQuery.ajax({
        url: "https:" + _ENV_ + "api/1.0.0-beta/urlManager/getParameter",
        type:"get",
        contentType:"application/json",
        data:{
            "md5":gs_all_params.gs_md5,
            "rt":new Date().getTime()
        },
        xhrFields: {
            withCredentials: true
        },
        success:function(response){
            window[APP_ENV].gs_params =Object.assign(response.Parameter,gs_all_params) ;
            createApp();
        },
        error:function() {
        }
});

運行後,不再報錯並且得到了正確的結果。

總結:
出現這個問題,是因爲本人對跨域請求帶上原網站的cookie的相關知識不太瞭解,通過這次報錯正好學習到了,因此記錄下來供大家借鑑。

發佈了42 篇原創文章 · 獲贊 28 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章