MVC认证和防伪令牌迪朗达尔SPA模板 [英] MVC Authentication and Antiforgery token with Durandal SPA template

查看:382
本文介绍了MVC认证和防伪令牌迪朗达尔SPA模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我有一个身份验证服务(见下文),我在迪朗达尔添加作为依赖 main.js 。该服务名为:

 认证

在我的 main.js 我称之为

  authentication.handleUnauthorizedAjaxRequest(函数(){
        app.showMessage(您没有权限,请登录')
        。然后(函数(){
            router.navigateTo('#/用户/注册');
        });
    });

报告警告说,他们没有被授权的用户,用户导航到登录视图/视图模型在那里他们可以输入详细信息,并尝试登录。

建设这个认证视图模型时,浮现在脑海中的一些问题:


  • 是否有与我在做什么什么明显的问题?

  • 这是我如何'意味着'做事迪朗达尔?

  • 是我重新发明轮子呢?我看不出在迪朗达尔这样的事。

大多数人似乎要创建单独的 CSHTML 页面;一个用于登录(如果用户没有通过验证),和平常的 index.cshtml 有没有什么好的理由我切换到该方法?

我的服务器端的用户控制器在我的登录操作有[ValidateAntiForgeryToken]属性我需要发送这一点。结果
我也有一个'防伪'服务(见下文),这也是我在我的 main.js 视图模型文件添加为一个依赖
然后(也在我main.js)。

  antiforgery.addAntiForgeryTokenToAjaxRequests();

这拦截(连同内容)所有Ajax请求,并增加了MVC AntiForgeryToken价值的数据。
似乎正是工作,我希望它。请让我知道如果有任何错误/错误。

填写以下认证服务。

  //服务/ authentication.js
定义(功能(需要){
    VAR系统=要求(迪朗达尔/系统),
    应用=要求(迪朗达尔/应用程序),
    路由器=要求(迪朗达尔/插件/路由器');    返回{
        handleUnauthorizedAjaxRequests:函数(回调){
            如果(!回调){
                返回;
            }
            (文档)$ .ajaxError(函数(事件,要求,选项){
                如果(request.status === 401){
                    回电话();
                }
            });
        },        canLogin:功能(){
            返回true;
        },
        登录:功能(用户信息,的navigateToUrl){
            如果(!this.canLogin()){
                返回system.defer(功能(DFD){
                    dfd.reject();
                })。诺言();
            }
            VAR jqxhr = $。员额(/用户/登录,用户信息)
                .done(功能(数据){
                    如果(data.success ==真){
                        如果(!的navigateToUrl){
                            router.navigateTo(的navigateToUrl);
                        }其他{
                            返回true;
                        }
                    }其他{
                        返回的数据;
                    }
                })
                .fail(功能(数据){
                    返回的数据;
                });            返回jqxhr;
        }
    };
});//服务/ antiforgery.js
定义(功能(需要){
    VAR应用=要求(迪朗达尔/应用');    返回{
        / *这个拦截所有Ajax请求(与内容)
            并添加了MVC AntiForgeryToken值到数据
            使之与[ValidateAntiForgeryToken]属性控制器的行动将不会失败            最初的想法来自http://stackoverflow.com/questions/4074199/jquery-ajax-calls-and-the-html-antiforgerytoken来了            使用此            1)确保以下内容添加到您的迪朗达尔Index.cshml
            <表ID =__ AjaxAntiForgeryForm行动=#的方法=后>
                @ Html.AntiForgeryToken()
            < /表及GT;            2)在main.js确保该模块被添加作为一个依赖            3)在main.js添加以下行
            antiforgery.addAntiForgeryTokenToAjaxRequests();        * /
        addAntiForgeryTokenToAjaxRequests:功能(){
            VAR令牌= $('#__ AjaxAntiForgeryForm输入[名称= __ RequestVerificationToken]')VAL()。
            如果(!标记){
                app.showMessage('错误:身份验证服务找不到__RequestVerificationToken');
            }
            VAR tokenParam =__RequestVerificationToken =EN + codeURIComponent(标记);            (文档)$ .ajaxSend(函数(事件,要求,选项){
                如果(options.hasContent){
                    options.data = options.data? [options.data,tokenParam]。加入(与&):tokenParam;
                }
            });
        }    };
});


解决方案

我preFER传递防伪标记在标题中。这样,它很容易解析出服务器上的请求,因为它不是你的表单的数据混合在一起。

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

<我一个href=\"http://stackoverflow.com/questions/15416264/validateantiforgerytoken-with-spa-architecture/15512292#15512292\">created后已经就如何做到这一点。

Some areas of my SPA need to be open to all users, and some areas require authentication. In these areas, it's the data loaded via AJAX that I want to protect.

I have an authentication service (see below), which I add as a dependency in my durandal main.js. The service is called:

authentication

In my main.js I call

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

It warns the user they are not authorized, and navigates user to a login view/viewmodel where they can enter details and try logging in.

Some questions that come to mind when building this authentication viewModel:

  • Are there any obvious concerns with what I'm doing?
  • Is this how I'm 'meant' to do things in Durandal?
  • Am I re-inventing the wheel? I couldn't see anything like this within Durandal.

Most people seem to be creating seperate cshtml pages; one for login (if the user is not authenticated), and the usual index.cshtml Is there any good reasons for me to switch to that method?

My login action on my the server-side 'user controller' has the [ValidateAntiForgeryToken] attribute I need to send that as well.
I also have an 'antiforgery' service (see below) which I also add as a dependency in my main.js viewModel file then (also in my main.js).

antiforgery.addAntiForgeryTokenToAjaxRequests();

This intercepts all ajax requests (along with content), and adds the MVC AntiForgeryToken value to the data. Seems to work exactly as I want it to. Please let me know if there's any errors/mistakes.

Complete authentication service below.

// 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;
                }
            });
        }

    };
});

解决方案

I prefer to pass the antiforgery token in the header. This way its easy to parse out of the request on the server because its not intermingled with your form's data.

I then created a custom action filter to check for the antiforgery token.

I created a post already on how to do this.

这篇关于MVC认证和防伪令牌迪朗达尔SPA模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆