1. 程式人生 > >CROS Ajax 跨域請求中攜帶 cookie 做身份認證 (xhr withCredentials屬性)

CROS Ajax 跨域請求中攜帶 cookie 做身份認證 (xhr withCredentials屬性)

好吧,一如既往的短篇記錄性文章,記下坑供查閱

原因大概是這樣的,公司有很多內網的服務系統,同屬於同一個主域,但是是不同的子域,然後呢,當在一個系統需要呼叫另一個系統的時候,就會出現跨域的問題。所以呢,我們打算寫一個通用代理程式來做中轉,然後呢,先簡單貼一下程式碼吧

var server = http.createServer(function(request, response) {
    ...
 
    var options = {
        hostname: address.hostname,
        port: address.port || 80,
        path: address.path,
        method: request.method,
        headers: request.headers,
    };
 
    options.headers.host = address.host;
 
    var proxy = http.request(options, function(res) {
 
        for(var key in res.headers) {
            response.setHeader(key, res.headers[key]);
        }
 
        response.setHeader("Access-Control-Allow-Origin", "*");
 
        res.pipe(response);
    });
 
    request.pipe(proxy);
});

嗯嗯,大概就是這樣的

但是,馬上我們就發現了問題,是的,事情總不會這麼順利。接下來我們發現,因為這個代理 Server 和 web 也不是同一個子域,所以雖然我們添加了允許跨域的頭,但是會發現,傳送到後端的 POST 跨域請求並沒有攜帶 cookie 資訊,然後也就沒有辦法得到另一個服務系統的認證。

OK,當我們手動在 ajax 請求中把 cookie 新增到頭資訊中的時候,像下面這樣

$.ajax({
    ...
    headers: {"Cookie": document.cookie},
    ...
});

但是瀏覽器會提示這是一個不安全的操作,然後就。。。。 華麗麗的拒絕掉了

然後我們試著用 withCredentials 帶上 cookie,大概是這個樣子

$.ajax({
    ...
    xhrFields: {
        withCredentials: true
    }
});

然後呢,我們需要在我們的 Server 返回的時候加上一條頭資訊

response.setHeader("Access-Control-Allow-Credentials", true);

然後,是的,你會發現瀏覽器又給你報了一條錯誤,提示你 Access-Control-Allow-Origin 不能用 *

 萬用字元。

聽起來好像很合理,如果你想用一個域的 cookie 來認證的話,就指定一下這個域,很合理的要求,那麼,當我們的想寫一個通用的代理程式,希望任何一個域名都可以通過它的 cookie 來認證它要代理的 API 介面時,要怎麼辦?

聽上去好像不是一個合理的需求,當時貌似,還真的有辦法,就是再返回的時候,把請求的域填寫進頭資訊裡,就是誰訪問我,我允許誰,程式碼大概就是這樣的

response.setHeader("Access-Control-Allow-Credentials", true);
response.setHeader("Access-Control-Allow-Origin", request.headers.origin);

嗯嗯,就是這樣啦,雖然感覺最後並不是一個很正確的方式,但是也算是解決了我們奇葩的需求了

今天就先這樣吧,拜拜~

tips:java程式碼獲取請求方地址

request.getHeader("Origin");