Pregunta MVC Authentication and Antiforgery token with Durandal SPA template


Algunas áreas de mi SPA deben estar abiertas a todos los usuarios, y algunas áreas requieren autenticación. En estas áreas, son los datos cargados a través de AJAX los que quiero proteger.

Tengo un servicio de autenticación (ver a continuación), que agrego como una dependencia en mi durandal main.js. El servicio se llama:

authentication

En mi main.js Yo lo llamo

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

Advierte al usuario que no está autorizado, y lleva al usuario a una vista de inicio de sesión / modelo de vista donde pueden ingresar detalles e intentar ingresar.

Algunas preguntas que vienen a la mente al construir esta autenticación viewModel:

  • ¿Hay alguna preocupación obvia con lo que estoy haciendo?
  • ¿Es así como 'pretendía' hacer las cosas en Durandal?
  • ¿Estoy reinventando la rueda? No pude ver nada como esto en Durandal.

La mayoría de las personas parecen estar creando separadamente cshtml páginas; uno para iniciar sesión (si el usuario no está autenticado) y el habitual index.cshtml ¿Hay alguna buena razón para que cambie a ese método?

Mi acción de inicio de sesión en mi "controlador de usuario" del lado del servidor tiene el atributo [ValidateAntiForgeryToken] que necesito enviar también.
También tengo un servicio 'antiforgery' (ver a continuación) que también agrego como una dependencia en mi main.js viewModelo luego (también en mi main.js).

antiforgery.addAntiForgeryTokenToAjaxRequests();

Esto intercepta todas las solicitudes ajax (junto con el contenido) y agrega el valor de MVC AntiForgeryToken a los datos. Parece que funciona exactamente como yo quiero. Por favor, avíseme si hay errores / errores.

Complete el servicio de autenticación a continuación.

// 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


origen


Respuestas:


Prefiero pasar el token antiforgery en el encabezado. De esta forma es fácil analizar la solicitud en el servidor porque no está entrelazada con los datos de su formulario.

Luego creé un filtro de acción personalizado para verificar el token antiforgery.

yo creó una publicación Ya sobre cómo hacer esto.


14
2018-04-05 22:07