jquery - MVC Authentication and Antiforgery token with Durandal SPA template -
some areas of spa need open users, , areas require authentication. in these areas, it's data loaded via ajax want protect.
i have authentication service (see below), add dependency in durandal main.js. service called:
authentication
in main.js call
authentication.handleunauthorizedajaxrequest(function () { app.showmessage('you not authorized, please login') .then(function () { router.navigateto('#/user/login'); }); });
it warns user not authorized, , navigates user login view/viewmodel can enter details , try logging in.
some questions come mind when building authentication viewmodel:
- are there obvious concerns i'm doing?
- is how i'm 'meant' things in durandal?
- am re-inventing wheel? couldn't see within durandal.
most people seem creating seperate cshtml pages; 1 login (if user not authenticated), , usual index.cshtml there reasons me switch method?
my login action on server-side 'user controller' has [validateantiforgerytoken] attribute need send well.
have 'antiforgery' service (see below) add dependency in main.js viewmodel file (also in main.js).
antiforgery.addantiforgerytokentoajaxrequests();
this intercepts ajax requests (along content), , adds mvc antiforgerytoken value data. seems work want to. please let me know if there's 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 { /* intercepts ajax requests (with content) , adds mvc antiforgerytoken value data controller actions [validateantiforgerytoken] attribute won't fail original idea came http://stackoverflow.com/questions/4074199/jquery-ajax-calls-and-the-html-antiforgerytoken use 1) ensure following added durandal index.cshml <form id="__ajaxantiforgeryform" action="#" method="post"> @html.antiforgerytoken() </form> 2) in main.js ensure module added dependency 3) in main.js add following line antiforgery.addantiforgerytokentoajaxrequests(); */ addantiforgerytokentoajaxrequests: function () { var token = $('#__ajaxantiforgeryform input[name=__requestverificationtoken]').val(); if (!token) { app.showmessage('error: authentication service 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 pass antiforgery token in header. way easy parse out of request on server because not intermingled form's data.
i created custom action filter check antiforgery token.
i created post on how this.
Comments
Post a Comment