Angular企業級開發(9)-前后端分離之后添加驗證碼


1.背景介紹

團隊開發的項目,前端基於Bootstrap+AngularJS,后端Spring MVC以RESTful接口給前端調用。開發和部署都是前后端分離。項目簡單部署圖如下,因為后台同時采用微服務的方式,所以后台不止3個,畫圖示意。終極方案是采用Docker,在前端和后台調用中間添加一層:API Gateway。

部署圖

因為考慮到和其他系統集成的可能性,所以在登錄這一塊使用了Token來做登錄,認證服務器負責生成Token和驗證Token。因為客戶需要提高系統的安全性,需要在登錄頁添加一個驗證碼。但是因為項目是基於前后端分離的,所以添加驗證碼的功能還是有一些不一樣。

登錄頁

2.Session解決方案

有經驗的開發者第一反應就是之前驗證碼怎么添加的,現在在這里也是同樣的道理,為什么不一樣呢?因為前后端分離,系統登錄使用的是Token,后台不再設置Session了。后台必須保證當前用戶輸入的驗證碼是用戶開始請求頁面時候的驗證碼,必須保證驗證碼的唯一性。舉個例子:

A用戶看到的驗證碼是:ABC;B用戶看到的驗證碼是:DEF。后台存儲了ABC和DEF這2個驗證碼,如果不限定A用戶輸入的驗證碼是ABC,那么當A用戶碰巧輸入DEF,然后用戶名和密碼也是正確的話,A用戶也是可以登錄系統的。

在早期可以使用Session系統中,后台返回驗證碼信息同時寫入一個session,有一個SessionID的字段和當前這個驗證碼對應。所以當用戶輸入用戶名、密碼和驗證碼的時候,瀏覽器自動把存有session信息的cookie發送到服務器,服務器基於Session可以判斷當前這個驗證碼確實是A用戶應該要輸入的。

缺點:為了考慮到后續和其他系統集成,同時后台部署是多台服務器,采用的API網關。已經使用了Token,如果為了驗證碼這個功能,引入Session,有點得不償失。

3.無Session解決方案

不能使用Session,那只能考慮無Session的方案。要同時獲取驗證碼和驗證碼對應的一個id值。作為前端的我,第一反應是通過AngularJS中的$http請求去獲取。但是后台驗證碼是直接讀取圖片返回二進制流格式給到前端,所以不能額外返回一個ID字段。后端開發同事就說,那在Response Header里面返回一個id的字段,和驗證碼的值相關聯起來。到現在聽起來一切都很順利。前端代碼如下:

//控制器層代碼
$scope.getCaptcha = function () {
    loginService.getCaptcha().success(function (response, status, headers) {
      $scope.id = headers().id;

      if (response.size > 0) {
        $scope.verificationImage = window.URL.createObjectURL(response);
      } else {
        toastr.error("獲取驗證碼失敗:" + response.message);
      }

    }).error(function (response) {
      console.log(response);
    });
  }
//服務層代碼
getCaptcha: function () {
    return $http({
    method: "GET",
    responseType: "blob",
    url: AppConfig.userServerUrl + "/user/Captcha/request"
    });
},

前端AngularJS代碼無法獲取header頭部額外字段,能獲取的字段如下:

在stackoverflow上搜索一番,解決辦法是后台需要設置允許前端瀏覽器能獲取header頭部里面的字段。后台同事修改之后,response header里面信息如下圖所示:

同域和跨越解決辦法:How to read response headers in angularjs?

4.IE9下的bug

以為大功告成,然后在IE9瀏覽器上測試一下,發現無法加載到驗證碼,而且控制台報錯誤。折騰半天,發現IE9不支持window.URL.createObjectURL();,而且AngularJS發送請求加載二進制流文件就報錯。

為了支持IE9,目前解決方法是讓后台不返回二進制流文件,而是返回base64編碼的字符串,這樣IE9也是支持的。

5.可選一種方式

和之前同事交流一番,同事提出了一個可選的方案。因為我們在請求驗證碼的時候有2個內容,一個是驗證碼id,一個驗證碼圖片。其實驗證碼id可以在前端使用隨機數生成一個,然后前端把這個id傳入后台,后台根據這個id,然后加一些特殊字符,拼接之后一個唯一字符,同時生成一個圖片,這個唯一字符和這個驗證碼圖片關聯起來,然后將圖片返回base64編碼內容返回到前端。這種可以不需要前端發送Ajax請求,直接在圖片上使用ng-src

<img ng-src="http://www.example.com?uid=1001cmss" >

參考文檔

淺談COOKIE和SESSION關系和區別等


免責聲明!

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



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