前后端分離,解決跨域問題及django的csrf跨站請求保護


1. 前后端分離解決跨域問題

解決跨域調用服務並設置headers 主要的解決方法需要通過服務器端設置響應頭、正確響應options請求,正確設置 JavaScript端需要設置的headers信息 方能實現;

關於跨域,前端會先發送OPTIONS請求,進行預檢,檢查后端是否允許前端設置的相應的請求頭,請求內容

 

  function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');

    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    $.ajaxSetup({
        crossDomain: false, // obviates need for sameOrigin test
        beforeSend: function(xhr, settings) {
            if (!csrfSafeMethod(settings.type)) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    });
官方js解決csrf

- 瀏覽器error: 添加了官方解決csrftoken的js代碼后,報跨域錯誤

Failed to load http://127.0.0.1/course/api/signup/check_username/: Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers in preflight response.

Failed to load http://127.0.0.1/course/api/signup/check_username/: Request header field X-CSRFToken is not allowed by Access-Control-Allow-Headers in preflight response.

- 后端error:

Forbidden (CSRF cookie not set.): /course/api/signup/check_username/
[26/Nov/2018 16:23:06] "POST /course/api/signup/check_username/ HTTP/1.1" 403 2857
```
- 解決方案是在django后端豁免跨域的中間件中添加對應的header,可以解決跨域
```
class AllowOriginMiddleware(MiddlewareMixin):
"""解決跨域"""

def process_response(self, request, response):
# 簡單請求
response['Access-Control-Allow-Origin'] = '*'
# 復雜請求,會先發送預檢請求OPTIONS
if request.method == 'OPTIONS':
response['Access-Control-Allow-Headers'] = 'Content-Type,X-Requested-With,X-CSRFToken'
response['Access-Control-Allow-Methods'] = 'POST,PUT,PATCH,DELETE'
return response
```

 

 

 

 

 

 

 

 

 

 

 

 

前后端分離解決django的csrf攔截:

方法1、簡單暴力,后端注銷django的csrf中間件  'django.middleware.csrf.CsrfViewMiddleware',

方法2、不注銷csrf中間件,后端通過django提供的裝飾器,為特定的視圖加上裝飾器進行csrf的豁免  

from django.views.decorators.csrf import csrf_exempt,csrf_protect

FBV:
    直接在函數上方加裝飾器  @csrf_exempt  即可不驗證csrf

CBV:
    必須導入:from django.utils.decorators import method_decorator

    經測試在CBV上必須在類上加且只能給dispatch方法加
    
    # 直接在類上面加
@method_decorator(wapper_name, name='post')    #給方法post加裝飾器
@method_decorator(wapper_name, name='get')
class AddClass(View)

注:其實也可以直接給View中的dispatch方法加裝飾器,這樣同樣可以實現給自己類下的所有方法加裝飾器(自己未定義dispatch方法時)
@method_decorator(wapper_name, name='dispatch')
class AddClass(View)


注:如果注銷了csrf中間件,也可以通過裝飾器為個別視圖添加csrf保護  

 方式3:

django中使用Ajax請求的CSRF設置

將官方文檔上的ajax設置照搬下來:

----js代碼

function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });

 

 

 

 

 

django前后端不分離解決csrf:

前后端不分離解決csrf

form表單發送:
1. 前端模板中需要加{% csrf_token%},本質是生成一個type類型為hidden的input標簽,name=csrfmiddlewaretoken value= 隨機字符串
2. form表單,post請求直接發送
注: 如不加csrf_token標簽,form的post想成功,就智能注銷后端的csrf中間件了

ajax發送:
3. 前端模板中加{% csrf_token%},
方式1:在ajax中的data中加 `'csrfmiddlewaretoken': $("[name='csrfmiddlewaretoken']").val(),`

方式2:在ajax中添加header:`headers:{“X-CSRFToken”:$("name='csrfmiddlewaretoken'").val()}`

方式3:通過js全局設置,和上面的方式2一樣本質是從cookie中獲取  【此方法也是前后端分離,前端解決csrf的官方推薦方案】

具體見博客:(https://www.cnblogs.com/sunxiuwen/p/9675448.html#_label13)

 

------------------------------------------------------------------------網友見解----------------------------------------------------------------

ajax 跨域 headers JavaScript ajax 跨域請求 +設置headers 實踐

解決跨域調用服務並設置headers 主要的解決方法需要通過服務器端設置響應頭、正確響應options請求,正確設置 JavaScript端需要設置的headers信息 方能實現。

此處手札 供后人參考~

1.第一步 服務端設置響應頭

header('Access-Control-Allow-Origin:*');  //支持全域名訪問,不安全,部署后需要固定限制為客戶端網址

header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支持的http 動作

header('Access-Control-Allow-Headers:x-requested-with,content-type');  //響應頭 請按照自己需求添加。

2.第二部 了解IE chrome 等瀏覽器 對於 跨域請求並要求設置Headers自定義參數的時候的 "預請求"   就是如果遇到 跨域並設置headers的請求,所有請求需要兩步完成!

A 第一步:發送預請求 OPTIONS 請求。此時 服務器端需要對於OPTIONS請求作出響應 一般使用202響應即可 不用返回任何內容信息。(能看到這份手稿的人,本人不相信你后台處理不了一個options請求)

B 第二步:服務器accepted 第一步請求后 瀏覽器自動執行第二步 發送真正的請求。此時 大多數人 會發現請求成功了,但是 有那么幾個人會發現 請求成功了但是沒有任何信息返回 why?因為你自定義的請求頭在服務器響應中不存在!

查看console輸出 會發現一個問題:

“Access-Control-Allow-Headers 列表中不存在請求標頭 XXXXXX”【IE】,

request header field xxxxxx is not allowed by Access-Control-Allow-Header【chrome】

這是因為 你的XXXX請求頭 沒有在服務器端被允許哦~

遇到這個問題 只有通過修改服務器端來完成,舉例:需要設置 requesttype這么一個自定義頭,那么 你需要在 服務端里面 將header('Access-Control-Allow-Headers:x-requested-with,content-type,requesttype');  同學們自行體會吧 這種語法就是根據“,”分割 自己需要設置什么頭,必須要在 服務端請求的響應頭里面設置好,不然客戶端永遠永遠提交不上去!

至此  JavaScript/ajax  跨域+ 修改httpheader 任務完美實現。前端 后端完全分離 大道自成!前后期分離迎來曠古的潮流

 次處作為見證 2016年1月25日20:21:28

"人們都一直在抱怨 JavaScript同源策略限制了web前端的發展!然而是服務端做的不夠細致!"

部分代碼參考如下:代碼只是提供了思想,具體步驟還要根據以上的文字 自行揣摩實現。以上內容看不懂 說明對於web一點也不了解,需要買本書看看嘍~(

客戶端代碼:

 

服務器端代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM