Pertanyaan Autentikasi MVC dan Antiforgery dengan template Durandal SPA


Beberapa area SPA saya harus terbuka untuk semua pengguna, dan beberapa area memerlukan otentikasi. Di area ini, itu adalah data yang dimuat melalui AJAX yang ingin saya lindungi.

Saya memiliki layanan otentikasi (lihat di bawah), yang saya tambahkan sebagai ketergantungan dalam durandal saya main.js. Layanan ini disebut:

authentication

Di dalam saya main.js Saya menelepon

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

Ini memperingatkan pengguna bahwa mereka tidak berwenang, dan menavigasi pengguna ke tampilan log masuk / model tampilan tempat mereka dapat memasukkan detail dan mencoba masuk.

Beberapa pertanyaan yang muncul dalam pikiran ketika membangun tampilan autentikasi ini:

  • Apakah ada kekhawatiran yang jelas dengan apa yang saya lakukan?
  • Apakah ini cara saya 'dimaksudkan' untuk melakukan sesuatu di Durandal?
  • Apakah saya sedang menciptakan roda? Saya tidak bisa melihat hal seperti ini di Durandal.

Kebanyakan orang tampaknya menciptakan terpisah cshtml halaman; satu untuk login (jika pengguna tidak diautentikasi), dan yang biasa index.cshtml Apakah ada alasan bagus bagi saya untuk beralih ke metode itu?

Tindakan login saya di 'pengontrol pengguna' sisi server saya memiliki atribut [ValidateAntiForgeryToken] yang saya perlukan untuk mengirim itu juga.
Saya juga memiliki layanan 'antiforgery' (lihat di bawah) yang juga saya tambahkan sebagai ketergantungan pada saya main.js file viewModel kemudian (juga di main.js saya).

antiforgery.addAntiForgeryTokenToAjaxRequests();

Ini memotong semua permintaan ajax (bersama dengan konten), dan menambahkan nilai MVC AntiForgeryToken ke data. Tampaknya berfungsi persis seperti yang saya inginkan. Tolong beri tahu saya jika ada kesalahan / kesalahan.

Lengkapi layanan otentikasi di bawah ini.

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

    };
});

32
2018-04-05 08:53


asal


Jawaban:


Saya lebih suka mengoper token antiforgery di header. Cara ini mudah untuk menguraikan permintaan pada server karena tidak berbaur dengan data formulir Anda.

Saya kemudian membuat filter tindakan kustom untuk memeriksa token antiforgery.

saya membuat pos sudah tentang cara melakukan ini.


14
2018-04-05 22:07