2013-04-05 52 views
32

我的SPA的某些區域需要向所有用戶開放,並且某些區域需要身份驗證。在這些領域中,通過AJAX加載的數據是我想要保護的。帶Durandal SPA模板的MVC身份驗證和防僞令牌

我有一個身份驗證服務(見下文),我在我的durandal main.js中添加了一個依賴項。該服務被稱爲:

authentication 

在我main.js我打電話

authentication.handleUnauthorizedAjaxRequest(function() { 
     app.showMessage('You are not authorized, please login') 
     .then(function() { 
      router.navigateTo('#/user/login'); 
     }); 
    }); 

報告警告說,他們沒有被授權用戶,並且用戶導航到登錄視圖/視圖模型,他們可以進入細節和嘗試登錄

建設這個認證視圖模型時,浮現在腦海中的一些問題:

  • 有什麼明顯的擔心我在做什麼?
  • 這就是我在Durandal做事的意思嗎?
  • 我重新發明了車輪嗎?我在杜蘭達看不到這樣的東西。

大多數人似乎正在創造分開cshtml頁;一個用於登錄(如果用戶未通過身份驗證),以及通常的index.cshtml是否有任何理由讓我切換到該方法?

我在服務器端「用戶控制器」上的登錄操作具有我需要發送的[ValidateAntiForgeryToken]屬性。
我也有一個'antiforgery'服務(見下文),我也添加作爲依賴我的main.js viewModel文件 然後(也在我的main.js中)。

antiforgery.addAntiForgeryTokenToAjaxRequests(); 

這攔截(連同內容)所有Ajax請求,並增加了MVC AntiForgeryToken值數據。 似乎完全按照我的意願工作。請讓我知道是否有任何錯誤/錯誤。

下面是完整的認證服務。

// services/authentication.js 
define(function (require) { 
    var system = require('durandal/system'), 
    app = require('durandal/app'), 
    router = require('durandal/plugins/router'); 

    return { 
     handleUnauthorizedAjaxRequests: function (callback) { 
      if (!callback) { 
       return; 
      } 
      $(document).ajaxError(function (event, request, options) { 
       if (request.status === 401) { 
        callback(); 
       } 
      }); 
     }, 

     canLogin: function() {   
      return true; 
     }, 
     login: function (userInfo, navigateToUrl) { 
      if (!this.canLogin()) { 
       return system.defer(function (dfd) { 
        dfd.reject(); 
       }).promise(); 
      } 
      var jqxhr = $.post("/user/login", userInfo) 
       .done(function (data) { 
        if (data.success == true) { 
         if (!!navigateToUrl) { 
          router.navigateTo(navigateToUrl); 
         } else { 
          return true; 
         } 
        } else { 
         return data; 
        } 
       }) 
       .fail(function (data) { 
        return data; 
       }); 

      return jqxhr; 
     } 
    }; 
}); 

// services/antiforgery.js 
define(function (require) { 
    var app = require('durandal/app'); 

    return { 
     /* this intercepts all ajax requests (with content) 
      and adds the MVC AntiForgeryToken value to the data 
      so that your controller actions with the [ValidateAntiForgeryToken] attribute won't fail 

      original idea came from http://stackoverflow.com/questions/4074199/jquery-ajax-calls-and-the-html-antiforgerytoken 

      to use this 

      1) ensure that the following is added to your Durandal Index.cshml 
      <form id="__AjaxAntiForgeryForm" action="#" method="post"> 
       @Html.AntiForgeryToken() 
      </form> 

      2) in main.js ensure that this module is added as a dependency 

      3) in main.js add the following line 
      antiforgery.addAntiForgeryTokenToAjaxRequests(); 

     */ 
     addAntiForgeryTokenToAjaxRequests: function() { 
      var token = $('#__AjaxAntiForgeryForm  input[name=__RequestVerificationToken]').val(); 
      if (!token) { 
       app.showMessage('ERROR: Authentication Service could not find  __RequestVerificationToken'); 
      } 
      var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(token); 

      $(document).ajaxSend(function (event, request, options) { 
       if (options.hasContent) { 
        options.data = options.data ? [options.data, tokenParam].join("&") :  tokenParam; 
       } 
      }); 
     } 

    }; 
}); 
+0

嗨斯圖爾特, 你的想法很好,我試圖將它應用在我的Hot Towel/Durandal項目中。我得到了auth和antiforgery服務,但我沒有獲得auth服務來攔截未經授權的用戶並將其重定向到登錄頁面。我怎麼做?我需要添加一些東西到Index.cshtml? 謝謝 – 2013-04-10 01:32:33

+0

這也是在Durandal的谷歌集團 - 有來自其他人的更新,我還添加了一些代碼示例 - 他們不會真正適合在這裏發表評論...所以;-) ..這裏是鏈接https://groups.google.com/forum/?hl=zh-CN&fromgroups=#!topic/durandaljs/iq9OPprfob0 – stooboo 2013-04-12 09:53:29

回答

14

我更喜歡在標題中傳遞防僞標記。這種方式很容易解析出服務器上的請求,因爲它不與表單的數據混合在一起。

然後我創建了一個自定義操作篩選器來檢查防僞標記。

created a post已經如何做到這一點。

+0

+1好主意,聽起來像是一個有效的地方! – mikekidder 2013-04-06 01:41:26

+0

乾杯埃文,我沒有考慮過放入標題(我沒有看到你的帖子,所以謝謝你的鏈接) – stooboo 2013-04-06 02:42:43