32 votes

Authentification MVC et jeton anti-falsification avec le modèle Durandal SPA

Certaines zones de mon SPA doivent être ouvertes à tous les utilisateurs, et d'autres nécessitent une authentification. Dans ces zones, ce sont les données chargées via AJAX que je veux protéger.

J'ai un service d'authentification (voir ci-dessous), que j'ajoute comme dépendance dans mon durandal main.js . Le service est appelé :

authentication

Dans mon main.js J'appelle

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

Il avertit l'utilisateur qu'il n'est pas autorisé et le dirige vers une vue/un modèle de connexion où il peut entrer des détails et essayer de se connecter.

Quelques questions qui viennent à l'esprit lors de la construction de ce viewModel d'authentification :

  • Y a-t-il des problèmes évidents avec ce que je fais ?
  • C'est comme ça que je suis "censé" faire les choses dans Durandal ?
  • Est-ce que je réinvente la roue ? Je n'ai rien vu de tel dans Durandal.

La plupart des gens semblent créer des sites séparés cshtml une page pour la connexion (si l'utilisateur n'est pas authentifié), et les pages habituelles de l'annuaire. index.cshtml Y a-t-il de bonnes raisons pour que je passe à cette méthode ?

Mon action de connexion sur mon "contrôleur utilisateur" côté serveur possède l'attribut [ValidateAntiForgeryToken] que je dois également envoyer.
Je dispose également d'un service "antiforgery" (voir ci-dessous) que j'ajoute également comme dépendance dans mon fichier main.js fichier viewModel puis (également dans mon main.js).

antiforgery.addAntiForgeryTokenToAjaxRequests();

Cela intercepte toutes les requêtes ajax (ainsi que le contenu), et ajoute la valeur MVC AntiForgeryToken aux données. Il semble que cela fonctionne exactement comme je le souhaite. S'il vous plaît laissez-moi savoir s'il ya des erreurs / erreurs.

Complétez le service d'authentification ci-dessous.

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

    };
});

14voto

Evan Larsen Points 4352

Je préfère passer le jeton anti-falsification dans l'en-tête. De cette façon, il est facile de l'extraire de la requête sur le serveur car il n'est pas mélangé aux données de votre formulaire.

J'ai ensuite créé un filtre d'action personnalisé pour vérifier la présence du jeton anti-falsification.

I a créé un poste déjà sur la façon de le faire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X