web-dev-qa-db-fra.com

Portée ou service d'accès dans le routeur ui onEnter pour vérifier l'accès (auth)

Ok, j'ai donc un état pour l'URL "/ securepage" que je dois vérifier chaque fois qu'un utilisateur essaie d'y accéder. J'ai donc lu une fonction onEnter que je peux utiliser. Mais je ne peux pas sembler avoir la portée ni un service à partir de là. Qu'est-ce que je fais mal?

        .state('securepage', {
            url: "/securepage",
            template: securepage.html,
            onEnter: function(){
                // if (!$scope.main.isAuthenticated) $state.go("/login");
                // if (!myLoginService.currentUser()) $state.go("/login");

Les options actuelles, à mon avis, consistent à utiliser résoudre et/ou vérifier l’authentification dans le contrôleur. Mais un contrôle d'authentification ne serait-il pas mieux placé dans onEnter?

27
joeriks

J'ai rencontré un problème similaire aujourd'hui. Nous avons passé une journée entière et avons finalement trouvé une solution viable autre que celles déjà suggérées ici.

Mon objectif principal est de trouver un moyen simple et efficace de sécuriser sélectivement certaines pages Web spécifiques. Le contrôle de sécurité doit être effectué avant le chargement ou l’appel du contrôleur HTML ou de l’un des contrôleurs correspondants. Si la vérification échoue, la page peut être transférée ailleurs sans aucun effet secondaire des autres contrôleurs.

J'ai essayé les autres approches suggérées. Chacun a son propre ensemble de problèmes:

  1. Utiliser OnEnter:

    • Il n'y a aucun moyen d'empêcher le routeur ui de poursuivre la transition d'état tout en effectuant un appel asynchrone pour effectuer le contrôle de sécurité.
  2. Utilisation de $ rootScope. $ On ('$ stateChangeStart'):

    • La gestion des états qui vérifient la sécurité requise sera séparée des définitions $ stateProvider.state (). Idéalement, je préférerais tout voir dans la définition d'un État défini en un seul endroit. Bien que ce ne soit pas un obstacle, ce n’est pas idéal.
    • Un problème beaucoup plus important est que l'événement $ stateChangeStart n'est pas appelé pour le chargement initial d'une page. Celui-ci est un obstacle.

Ma solution consiste à utiliser une fonction de résolution pour définir une promesse qui obligera les contrôleurs de vue à attendre que la requête différée soit terminée avant d'être appelée. Cela fonctionne parfaitement pour empêcher le contrôleur de démarrer de manière asynchrone.

Voici un aperçu du code que j'ai utilisé: 

.config(['$stateProvider', function ($stateProvider) {
    // Handler for Restricting Access to a page using the state.resolve call
    var accessRestrictionHandler = function($q, $rootScope, $state) {
            var deferred = $q.defer();

            // make sure user is logged in
            asyncCheckForLogin(function(status) {
                if (status != "Logged In") {
                    // You may save target page URL in cookie for use after login successful later
                    // To get the relative target URL, it is equal to ("#" + this.url).  
                    //      The "this" here is the current scope for the parent state structure of the resolve call.
                    $state.go("loginPage");
                }
                else    // if logged in, continue to load the controllers.  Controllers should not start till resolve() is called.
                    deferred.resolve();
            }.bind(this));

            return deferred.promise;
        };


    $stateProvider
        .state('userProfile', {
            url: '/userProfile',
            views: {
                'main': {
                    templateUrl: 'userProfile.html',
                    controller: 'userProfileCtrl'
                }
            },

            // SIMPLY add the line below to all states that you want to secure
            resolve: { loginRequired : accessRestrictionHandler } 
        })

        .state(.... some other state)
        .state(.... some other state);

}]);

J'espère que cela aidera certains d'entre vous.

15
Joe H

Une autre approche consisterait à faire en sorte qu'un service/contrôleur écoute l'événement "$ stateChangeStart". Là, vous pouvez vérifier si l’état appelé a besoin d’une authentification et rediriger la demande. Voici un extrait:

$rootScope.$on('$stateChangeStart', function (event, nextState, currentState) {
    if (!isAuthenticated(nextState)) {
        console.debug('Could not change route! Not authenticated!');
        $rootScope.$broadcast('$stateChangeError');
        event.preventDefault();
        $state.go('login');
    }
});

isAuthenticated pourrait mettre l'appel à vos services en attente, vérifier nextState.data pour les propriétés liées à l'authentification, etc.

14
Phil Thomas

Découvrez cette issue et this exemple depuis leur page github Cela devrait vous donner des indices.

7
Phil Thomas

Une réponse tardive mais bon je préfère l'écrire quand même. Je préfère ne pas toucher le $ rootScope dans la mesure du possible. Voici le code sur lequel je travaille actuellement qui résume une autre solution à votre question:

state('dash', {
                url:'/',
                views:{
                    "topNav":{
                        templateUrl:"user/dash/partials/top-nav.html",
                        controller:'logoutCtrl',
                    },
                    "sideNav":{
                        templateUrl:"user/dash/partials/side-nav.html"
                    },
                    "body":{
                        templateUrl:"user/dash/partials/body.html",
                        controller:'testCtrl'
                    }
                },
                onEnter: function(Auth, $state){
                    if(!AuthSvc.isAuthenticated){
                        $state.go('login');
                    }
                }
            })

J'utilise JWT pour stocker les jetons sur le stockage local en utilisant ngStorage, qui fournit un service $ localStorage que j'injecte dans l'usine Auth que j'ai injectée onEnter

0
Amin Mohamed Ajani