跨域set-cookie無效的解決方案

上次在項目中作一個手機驗證碼功能時遇到後端set-cookie沒法成功的問題,相信不少人都會遇到,今天分享出來,算是作個記錄,也給有須要的小夥伴一個參考,下面先說一下場景前端

手機驗證碼實現步驟

  1. 用戶輸入手機號並點擊發送驗證碼按鈕express

    此時是向後端服務器發起高請求,傳遞手機號碼
  2. 後端接收到手機號碼後經過短信服務商的接口發送短信到手機號後端

    因爲安全性問題,通常服務商的接口都是由後端發起請求,那驗證碼是怎麼來的呢?固然是咱們本身後端生成的(通常是生產一個4位或6位隨機數字號碼),短信接口只負責發送
  3. 用戶收到驗證碼後,在表單中輸入併發送驗證
  4. 後端收到驗證碼與第2步生成的進行校驗,一致則經過,不然不經過

問題來了,咱們都知道http請求是無狀態的,即每一個請求都是獨立的,兩個請求間沒有任何聯繫,但上面的步驟中,用戶發起了兩次請求(第1步和第3步),後端怎麼知道是同一我的呢?萬一當時有10我的同時獲取驗證碼,且都執行完全部步驟,怎麼實現各自第1和第3步的對應關係進而進行第4步校驗?因而咱們引入session跨域

什麼是session

session是保存的服務器的一個數據存儲機制,通常用於存儲用戶狀態數據,你能夠理解爲客戶端的cookie,由於它們很像,一樣是有key/value和有效時間,只是一個在服務端,一個在客戶端。這跟本文有什麼關係呢?確定有關係,關係大了去了,否則我寫幹嗎(自嗨中~~~)瀏覽器

咳~咳。。迴歸正題,剛剛說了http是無狀態的,而咱們如今又要把第1步和第3步關聯起來,怎麼關聯呢?session+cookie出馬,具體原理以下安全

  1. 第一次接到請求,後關會生成一個sessionid來標識當前會話(我使用express-session來實現),並經過set-cookie響應頭在客戶端生一個cookie,大概長這樣,服務器

    connect.sid=s%3Au9xG34DBU1vOVbIpCax0neMxL_Uc1fIC.4ndNJL5G%2B41DtUSLbQ%2BW75Z9wduOAON4lfu2JGTDe5
  2. 因爲cookie會自動發送給服務器,因此當前用戶後面的全部請求都會攜帶這個sessionid給服務器,服務器經過這個sessionid來標識是否爲同一個用戶,問題就迎刃而解了...

手機驗證碼功能具體實現步驟

  1. 前端:cookie

    1. 用戶輸入手機號,點擊獲取驗證碼
    2. 發送請求到後端,
  2. 後端:session

    1. 後端生成隨機驗證碼,保存在session,並給前端響應connect.sid(express-session會Set-Cookie響應頭)
    2. 並經過手機接口發送給用戶手機號(須要後端配置手機短信接口,通常須要購買,這裏不作額外說明)
  3. 前端:併發

    1. 瀏覽器接收到Set-Cookie響應頭後,自動把sessionid寫入瀏覽器cookie
    2. 用戶接收到手機驗證碼並填寫到對應輸入框
    3. 用戶點擊按鈕發送驗證碼到後端進行校驗(sessionidcookie自動發送到後端)
  4. 後端:

    1. 後端拿到驗證碼,並與第3步保存在session的隨機驗證碼進行比較,一致則響應成功,不然響應失敗

經過以上步驟,正常狀況下你已經能實現手機驗證碼功能了,可我恰恰遇到了非正常狀況,這也是我今天這篇文章的意義,因爲開發階段爲先後端分享,請求是產生了跨域,明明已經正確響應了Set-Cookie,容許了CORS跨域,但瀏覽器的cookie中就是看不到connect.sid的身影,關鍵瀏覽器還不報錯。

因而各類千里尋她千百度,最後發現Set-Cookie在跨域時默認是被瀏覽器忽略的,解決的方案是兩步:

  1. 後端設置"Access-Control-Allow-Credentials":true響應頭
  2. 前端發起請求時設置 withCredentials:true 請求頭

搞定,收工,但願對你有幫助

相關文章
相關標籤/搜索