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