32

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

承認されていないことをユーザーに警告し、詳細を入力してログインを試行できるログイン ビュー/ビューモデルにユーザーを移動します。

この認証ビューモデルを構築するときに頭に浮かぶいくつかの質問:

  • 私がしていることに明らかな懸念はありますか?
  • これが私がデュランダルで物事を行うための「意図された」方法ですか?
  • 私は車輪を再発明していますか?デュランダルの中では、そのようなものは見えませんでした。

ほとんどの人は、個別の cshtmlページを作成しているようです。1 つはログイン用 (ユーザーが認証されていない場合)、および通常のindex.cshtmlは、その方法に切り替える正当な理由はありますか?

サーバー側の「ユーザーコントローラー」でのログインアクションには、送信する必要がある [ValidateAntiForgeryToken] 属性もあります。
また、「偽造防止」サービス (以下を参照) もあり、main.js ビューモデル ファイル (これも 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;
                }
            });
        }

    };
});
4

1 に答える 1