带有 Durandal SPA 模板的 MVC 身份验证和防伪令牌

Posted

技术标签:

【中文标题】带有 Durandal SPA 模板的 MVC 身份验证和防伪令牌【英文标题】:MVC Authentication and Antiforgery token with Durandal SPA template 【发布时间】:2013-03-27 14:47:39 【问题描述】:

我的 SPA 的某些区域需要对所有用户开放,而某些区域需要身份验证。在这些区域中,我要保护的是通过 AJAX 加载的数据。

我有一个身份验证服务(见下文),我将其作为依赖项添加到我的 durandal ma​​in.js 中。服务被调用:

authentication

在我的 ma​​in.js 中我调用

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

它警告用户他们没有被授权,并将用户导航到登录视图/视图模型,他们可以在其中输入详细信息并尝试登录。

构建此身份验证视图模型时想到的一些问题:

我正在做的事情有什么明显的顾虑吗? 这就是我在 Durandal 的“本意”做事的方式吗? 我是在重新发明***吗?我在 Durandal 内看不到这样的东西。

大多数人似乎都在创建单独的 cshtml 页面;一个用于登录(如果用户未通过身份验证),以及通常的 index.cshtml 我是否有充分的理由切换到该方法?

我在服务器端“用户控制器”上的登录操作具有我需要发送的 [ValidateAntiForgeryToken] 属性。 我还有一个“防伪”服务(见下文),我还将它作为依赖项添加到我的 ma​​in.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://***.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;
                
            );
        

    ;
);

【问题讨论】:

嗨 Stuart,你的想法很棒,我正在尝试将它应用到我的 Hot Towel/Durandal 项目中。我获得了身份验证和防伪服务,但我没有获得身份验证服务来拦截未经授权的用户并将他们重定向到登录页面。我怎么做?我需要向 Index.cshtml 添加一些内容吗?谢谢 这也在 DurandalJs Google Group 上 - 那里有其他人的更新,我还添加了一些代码示例 - 它们不会真正适合这里的评论......所以;- ) .. 这是链接groups.google.com/forum/?hl=en&fromgroups=#!topic/… 【参考方案1】:

我更喜欢在标题中传递防伪令牌。这样很容易从服务器上解析出请求,因为它不会与表单的数据混合。

然后我创建了一个自定义操作过滤器来检查防伪令牌。

我created a post 已经知道如何做到这一点了。

【讨论】:

干杯埃文,我没想过要放入标题(我没有看到你的帖子,所以谢谢你的链接)

以上是关于带有 Durandal SPA 模板的 MVC 身份验证和防伪令牌的主要内容,如果未能解决你的问题,请参考以下文章

ASP.Net MVC 5 SPA 模板 OWin /token 导致“invalid_client”

如何使用基于令牌的 HTTP 基本身份验证保护 MVC 4 .NET SPA 模板中的 WebAPI?

如何将 Durandal#composition 集成到淘汰赛模板引擎中

Durandal js,所有功能在启动时激活

是否可以将单个MVC剃刀视图/页面转换为SPA?

Durandal Compose:激活方法并不总是被调用