1. 程式人生 > >前後端分離,解決跨域問題及django的csrf跨站請求保護 ajax 跨域 headers JavaScript ajax 跨域請求 +設定headers 實踐

前後端分離,解決跨域問題及django的csrf跨站請求保護 ajax 跨域 headers JavaScript ajax 跨域請求 +設定headers 實踐

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一點也不瞭解,需要買本書看看嘍~(

客戶端程式碼:

 

伺服器端程式碼