使用Durandal SPA模板的MVC身份验证和防伪签名

时间:2013-04-05 08:53:15

标签: jquery asp.net-mvc durandal

我的SPA的某些区域需要向所有用户开放,有些区域需要身份验证。在这些领域,我想通过AJAX加载数据。

我有一个身份验证服务(见下文),我在durandal main.js 中添加了一个依赖项。该服务被称为:

authentication

在我的 main.js 中,我致电

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

警告用户他们未获得授权,并将用户导航到登录视图/ viewmodel,在那里他们可以输入详细信息并尝试登录。

构建此身份验证viewModel时会想到一些问题:

  • 对我正在做的事情有任何明显的担忧吗?
  • 这是我在Durandal做事的意思吗?
  • 我是否重新发明了轮子?在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;
                }
            });
        }

    };
});

1 个答案:

答案 0 :(得分:14)

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

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

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