Autenticazione login ui-router AngularJS


376

Sono nuovo di AngularJS e sono un po 'confuso su come posso usare "ui-router" angolare nel seguente scenario:

Sto costruendo un'applicazione web che si compone di due sezioni. La prima sezione è la homepage con le sue viste di accesso e registrazione, e la seconda sezione è la dashboard (dopo aver effettuato correttamente l'accesso).

Ho creato un index.htmlper la sezione home con la sua app angolare e la ui-routerconfigurazione da gestire /logine le /signupviste, e c'è un altro file dashboard.htmlper la sezione dashboard con la sua app e la ui-routerconfigurazione per gestire molte viste secondarie.

Ora ho finito la sezione dashboard e non so come combinare le due sezioni con le loro diverse app angolari. Come posso dire all'app home di reindirizzare all'app dashboard?


1
Puoi condividere del codice con noi?
Chancho,

6
@Chancho Penso che non si tratti di codice, in realtà non so quale codice dovrei condividere.
Ahmed Hashem,

sì, per favore condividi il codice, domanda molto generica ...
Alireza,

Risposte:


607

Sto preparando una demo più bella e ripulendo alcuni di questi servizi in un modulo utilizzabile, ma ecco cosa ho pensato. Questo è un processo complesso per aggirare alcuni avvertimenti, quindi resta lì. Dovrai scomporlo in più pezzi.

Dai un'occhiata a questo plunk .

Innanzitutto, è necessario un servizio per memorizzare l'identità dell'utente. Io chiamo questo principal. Può essere verificato per vedere se l'utente ha effettuato l'accesso e, su richiesta, può risolvere un oggetto che rappresenta le informazioni essenziali sull'identità dell'utente. Questo può essere ciò di cui hai bisogno, ma gli elementi essenziali sarebbero un nome visualizzato, un nome utente, possibilmente un'e-mail e i ruoli a cui appartiene un utente (se questo si applica alla tua app). Principal ha anche metodi per eseguire i controlli di ruolo.

.factory('principal', ['$q', '$http', '$timeout',
  function($q, $http, $timeout) {
    var _identity = undefined,
      _authenticated = false;

    return {
      isIdentityResolved: function() {
        return angular.isDefined(_identity);
      },
      isAuthenticated: function() {
        return _authenticated;
      },
      isInRole: function(role) {
        if (!_authenticated || !_identity.roles) return false;

        return _identity.roles.indexOf(role) != -1;
      },
      isInAnyRole: function(roles) {
        if (!_authenticated || !_identity.roles) return false;

        for (var i = 0; i < roles.length; i++) {
          if (this.isInRole(roles[i])) return true;
        }

        return false;
      },
      authenticate: function(identity) {
        _identity = identity;
        _authenticated = identity != null;
      },
      identity: function(force) {
        var deferred = $q.defer();

        if (force === true) _identity = undefined;

        // check and see if we have retrieved the 
        // identity data from the server. if we have, 
        // reuse it by immediately resolving
        if (angular.isDefined(_identity)) {
          deferred.resolve(_identity);

          return deferred.promise;
        }

        // otherwise, retrieve the identity data from the
        // server, update the identity object, and then 
        // resolve.
        //           $http.get('/svc/account/identity', 
        //                     { ignoreErrors: true })
        //                .success(function(data) {
        //                    _identity = data;
        //                    _authenticated = true;
        //                    deferred.resolve(_identity);
        //                })
        //                .error(function () {
        //                    _identity = null;
        //                    _authenticated = false;
        //                    deferred.resolve(_identity);
        //                });

        // for the sake of the demo, fake the lookup
        // by using a timeout to create a valid
        // fake identity. in reality,  you'll want 
        // something more like the $http request
        // commented out above. in this example, we fake 
        // looking up to find the user is
        // not logged in
        var self = this;
        $timeout(function() {
          self.authenticate(null);
          deferred.resolve(_identity);
        }, 1000);

        return deferred.promise;
      }
    };
  }
])

In secondo luogo, è necessario un servizio che controlli lo stato in cui l'utente vuole recarsi, assicurandosi che siano connessi (se necessario; non necessario per l'accesso, reimpostazione della password, ecc.), Quindi esegue un controllo del ruolo (se l'app ne ha bisogno). Se non sono autenticati, inviarli alla pagina di accesso. Se sono autenticati, ma non riescono a controllare i ruoli, inviarli a una pagina di accesso negato. Chiamo questo servizio authorization.

.factory('authorization', ['$rootScope', '$state', 'principal',
  function($rootScope, $state, principal) {
    return {
      authorize: function() {
        return principal.identity()
          .then(function() {
            var isAuthenticated = principal.isAuthenticated();

            if ($rootScope.toState.data.roles
                && $rootScope.toState
                             .data.roles.length > 0 
                && !principal.isInAnyRole(
                   $rootScope.toState.data.roles))
            {
              if (isAuthenticated) {
                  // user is signed in but not
                  // authorized for desired state
                  $state.go('accessdenied');
              } else {
                // user is not authenticated. Stow
                // the state they wanted before you
                // send them to the sign-in state, so
                // you can return them when you're done
                $rootScope.returnToState
                    = $rootScope.toState;
                $rootScope.returnToStateParams
                    = $rootScope.toStateParams;

                // now, send them to the signin state
                // so they can log in
                $state.go('signin');
              }
            }
          });
      }
    };
  }
])

Ora tutto quello che dovete fare è ascoltare in su ui-routers'$stateChangeStart . Questo ti dà la possibilità di esaminare lo stato corrente, lo stato in cui vogliono andare e inserire il tuo controllo di autorizzazione. In caso contrario, è possibile annullare la transizione del percorso o passare a un percorso diverso.

.run(['$rootScope', '$state', '$stateParams', 
      'authorization', 'principal',
    function($rootScope, $state, $stateParams, 
             authorization, principal)
{
      $rootScope.$on('$stateChangeStart', 
          function(event, toState, toStateParams)
      {
        // track the state the user wants to go to; 
        // authorization service needs this
        $rootScope.toState = toState;
        $rootScope.toStateParams = toStateParams;
        // if the principal is resolved, do an 
        // authorization check immediately. otherwise,
        // it'll be done when the state it resolved.
        if (principal.isIdentityResolved()) 
            authorization.authorize();
      });
    }
  ]);

La parte difficile del tracciamento dell'identità di un utente è cercarla se hai già effettuato l'autenticazione (ad esempio, stai visitando la pagina dopo una sessione precedente e hai salvato un token di autenticazione in un cookie, o forse hai aggiornato una pagina o rilasciato su un URL da un collegamento). A causa del modo in cui ui-routerfunziona, è necessario che la tua identità venga risolta una volta, prima di verificare l'autenticazione. Puoi farlo usando ilresolve opzione nella tua configurazione di stato. Ho uno stato genitore per il sito da cui tutti gli stati ereditano, il che forza il principale ad essere risolto prima che accada qualsiasi altra cosa.

$stateProvider.state('site', {
  'abstract': true,
  resolve: {
    authorize: ['authorization',
      function(authorization) {
        return authorization.authorize();
      }
    ]
  },
  template: '<div ui-view />'
})

C'è un altro problema qui ... resolveviene chiamato solo una volta. Una volta completata la promessa di ricerca dell'identità, non verrà eseguito nuovamente il delegato di risoluzione. Quindi dobbiamo fare i tuoi controlli di autenticazione in due posti: una volta in base alla tua promessa di identità risolvendoresolve , che copre la prima volta che si carica l'app, e una volta dentro $stateChangeStartse la risoluzione è stata eseguita, che copre ogni volta che si naviga negli stati.

OK, quindi cosa abbiamo fatto finora?

  1. Verifichiamo quando l'app viene caricata se l'utente ha effettuato l'accesso.
  2. Tracciamo informazioni sull'utente che ha effettuato l'accesso.
  3. Li reindirizziamo per accedere allo stato per gli stati che richiedono l'accesso dell'utente.
  4. Li reindirizziamo a uno stato di accesso negato se non dispongono dell'autorizzazione per accedervi.
  5. Abbiamo un meccanismo per reindirizzare gli utenti allo stato originale richiesto, se ne avevamo bisogno per accedere.
  6. Siamo in grado di disconnettere un utente (deve essere collegato di concerto con qualsiasi codice client o server che gestisce il tuo ticket di autenticazione).
  7. Non è necessario inviare nuovamente gli utenti alla pagina di accesso ogni volta che ricaricano il browser o rilasciano un collegamento.

Dove andiamo da qui? Beh, è possibile organizzare i vostri stati in regioni che necessitano di accedere. E 'possibile richiedere agli utenti autenticati / autorizzati con l'aggiunta datadi rolesquesti stati (o un genitore di loro, se si vuole utilizzare l'ereditarietà). Qui, limitiamo una risorsa agli amministratori:

.state('restricted', {
    parent: 'site',
    url: '/restricted',
    data: {
      roles: ['Admin']
    },
    views: {
      'content@': {
        templateUrl: 'restricted.html'
      }
    }
  })

Ora puoi controllare stato per stato quali utenti possono accedere a un percorso. Altre preoccupazioni? Forse variando solo una parte di una vista in base al fatto che siano o meno connessi? Nessun problema. Usa il principal.isAuthenticated()o ancheprincipal.isInRole() con uno dei numerosi modi in cui è possibile visualizzare condizionalmente un modello o un elemento.

Innanzitutto, iniettare principalin un controller o altro e attenersi all'ambito in modo da poterlo utilizzare facilmente nella vista:

.scope('HomeCtrl', ['$scope', 'principal', 
    function($scope, principal)
{
  $scope.principal = principal;
});

Mostra o nascondi un elemento:

<div ng-show="principal.isAuthenticated()">
   I'm logged in
</div>
<div ng-hide="principal.isAuthenticated()">
  I'm not logged in
</div>

Ecc., Così via, così via. Ad ogni modo, nella tua app di esempio, avresti uno stato per la home page che consentirebbe agli utenti non autenticati di passare. Potrebbero avere collegamenti agli stati di accesso o di iscrizione o avere quei moduli integrati in quella pagina. Qualunque cosa ti vada bene.

Le pagine del dashboard potrebbero ereditare da uno stato che richiede l'accesso degli utenti e, per esempio, essere un Usermembro del ruolo. Tutta la roba di autorizzazione che abbiamo discusso dovrebbe fluire da lì.


28
Grazie, questo mi ha davvero aiutato a mettere insieme il mio codice. In una nota a margine, se si ottiene un ciclo di routing infinito (UI Router bug), provare $location.pathinvece di $state.go.
jvannistelrooy,

2
Questa è un'ottima risposta e mi ha aiutato molto. Quando imposto user = principal nel mio controller e provo a chiamare dire user.identity (). Nome nella mia vista per ottenere il nome utente attualmente connesso mi sembra di ottenere solo l'oggetto promessa {then: fn, catch: fn, finalmente :} restituito e non l'oggetto _identity effettivo. Se uso user.identity.then (fn (user)) posso ottenere l'oggetto utente ma questo sembra un sacco di codice per la vista, mi sto perdendo qualcosa?
Segna il

4
@ Ir1sh Vorrei prima risolvere l'identità nel controller e assegnarla a $scope.usernella tua thenfunzione. Puoi ancora fare riferimento usernei tuoi punti di vista; quando viene risolto, la vista verrà aggiornata.
moribvndvs,

2
@HackedByChinese Penso che la tua demo non funzioni più.
Blowsie,

7
@jvannistelrooy Ho avuto problemi con go () a, ma dopo averlo inserito dentro quindi dopo aver chiamato una funzione noop come questa $q.when(angular.noop).then(function(){$state.go('myState'), tutto funziona come previsto. Se chiamo $state.gomentre un'altra transizione di stato non è completata, allora non funzionerà (penso che sia la ragione per cui non funzionerà).
Sebastian,

120

Le soluzioni pubblicate finora sono inutilmente complicate, secondo me. C'è un modo più semplice. La documentazione diui-router dice ascolta $locationChangeSuccesse usa$urlRouter.sync() per controllare una transizione di stato, fermarla o riprenderla. Ma anche quello in realtà non funziona.

Tuttavia, qui ci sono due semplici alternative. Sceglierne uno:

Soluzione 1: ascolto attivo $locationChangeSuccess

Puoi ascoltare $locationChangeSuccesse puoi eseguire un po 'di logica, anche logica asincrona lì. Sulla base di tale logica, è possibile lasciare che la funzione ritorni indefinita, il che farà sì che la transizione di stato continui normalmente, oppure è possibile farlo $state.go('logInPage'), se l'utente deve essere autenticato. Ecco un esempio:

angular.module('App', ['ui.router'])

// In the run phase of your Angular application  
.run(function($rootScope, user, $state) {

  // Listen to '$locationChangeSuccess', not '$stateChangeStart'
  $rootScope.$on('$locationChangeSuccess', function() {
    user
      .logIn()
      .catch(function() {
        // log-in promise failed. Redirect to log-in page.
        $state.go('logInPage')
      })
  })
})

Tieni presente che ciò non impedisce il caricamento dello stato di destinazione, ma reindirizza alla pagina di accesso se l'utente non è autorizzato. Va bene dato che la vera protezione è sul server, comunque.

Soluzione 2: utilizzo dello stato resolve

In questa soluzione, si utilizza la ui-routerfunzione di risoluzione .

Fondamentalmente si rifiuta la promessa resolvese l'utente non è autenticato e quindi li reindirizza alla pagina di accesso.

Ecco come va:

angular.module('App', ['ui.router'])

.config(
  function($stateProvider) {
    $stateProvider
      .state('logInPage', {
        url: '/logInPage',
        templateUrl: 'sections/logInPage.html',
        controller: 'logInPageCtrl',
      })
      .state('myProtectedContent', {
        url: '/myProtectedContent',
        templateUrl: 'sections/myProtectedContent.html',
        controller: 'myProtectedContentCtrl',
        resolve: { authenticate: authenticate }
      })
      .state('alsoProtectedContent', {
        url: '/alsoProtectedContent',
        templateUrl: 'sections/alsoProtectedContent.html',
        controller: 'alsoProtectedContentCtrl',
        resolve: { authenticate: authenticate }
      })

    function authenticate($q, user, $state, $timeout) {
      if (user.isAuthenticated()) {
        // Resolve the promise successfully
        return $q.when()
      } else {
        // The next bit of code is asynchronously tricky.

        $timeout(function() {
          // This code runs after the authentication promise has been rejected.
          // Go to the log-in page
          $state.go('logInPage')
        })

        // Reject the authentication promise to prevent the state from loading
        return $q.reject()
      }
    }
  }
)

A differenza della prima soluzione, questa soluzione impedisce effettivamente il caricamento dello stato di destinazione.


6
@FredLackey dice che è presente un utente non autenticato state A. Fanno clic su un collegamento per andare a protected state Bma vuoi reindirizzarli logInPage. In caso contrario $timeout, ui-routerinterromperà semplicemente tutte le transizioni di stato, quindi l'utente rimarrà bloccato state A. Ciò $timeoutconsente ui-routerinnanzitutto di impedire la transizione iniziale protected state Bperché la risoluzione è stata rifiutata e, dopo averlo fatto, reindirizza a logInPage.
MK Safi,

Dove viene authenticateeffettivamente chiamata la funzione?
CodyBugstein,

La authenticatefunzione @Imray viene passata come parametro a ui-router. Non devi chiamarlo tu stesso. ui-routerlo chiama.
MK Safi,

Perché stai usando '$ locationChangeSuccess' invece di '$ stateChangeStart'?
Draex_8

@ PeterDraexDräxler Stavo principalmente seguendo la documentazione. Hai notato qualche differenza usando $stateChangeStart?
MK Safi,

42

La soluzione più semplice è utilizzare $stateChangeStarte event.preventDefault()annullare la modifica dello stato quando l'utente non è autenticato e reindirizzarlo allo stato di autenticazione che è la pagina di accesso.

angular
  .module('myApp', [
    'ui.router',
  ])
    .run(['$rootScope', 'User', '$state',
    function ($rootScope, User, $state) {
      $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
        if (toState.name !== 'auth' && !User.authenticaded()) {
          event.preventDefault();
          $state.go('auth');
        }
      });
    }]
  );

6
Non penso che funzionerà se User.authenticaded () è una chiamata asincrona. Questo è il Santo Graal che tutti cercano. Ad esempio, se tutti gli stati tranne "login" sono protetti, desidero confermare che l'utente è ancora autenticato PRIMA di caricare qualsiasi stato. L'uso di risolve fa schifo perché si risolvono solo una volta e per impedire il caricamento degli stati figlio, è necessario iniettare la risoluzione in OGNI BAMBINO .
Jason,

autenticato non è una chiamata asincrona nel mio caso: `this.authenticaded = function () {if (this.currentAccountID! == null) {return true; } return false; }; `
sebest

Secondo: stackoverflow.com/a/38374313/849829 , 'run' viene molto al di sopra di 'service e quindi i problemi. Controllare lo store locale per lo stato autenticato sembra essere un buon approccio.
Deepak Thomas,

22

Penso che tu abbia bisogno di uno serviceche gestisca il processo di autenticazione (e la sua memorizzazione).

In questo servizio avrai bisogno di alcuni metodi di base:

  • isAuthenticated()
  • login()
  • logout()
  • eccetera ...

Questo servizio deve essere iniettato nei controller di ciascun modulo:

  • Nella sezione Dashboard, utilizza questo servizio per verificare se l'utente è autenticato (service.isAuthenticated() metodo). in caso contrario, reindirizzare a / login
  • Nella sezione di accesso, basta utilizzare i dati del modulo per autenticare l'utente attraverso il service.login()metodo

Un esempio valido e solido per questo comportamento è l' app angolare del progetto e in particolare il suo modulo di sicurezza che si basa sul fantastico modulo di intercettore HTTP Auth

Spero che sia di aiuto


21

Ho creato questo modulo per aiutare a rendere questo processo un gioco da ragazzi

Puoi fare cose come:

$routeProvider
  .state('secret',
    {
      ...
      permissions: {
        only: ['admin', 'god']
      }
    });

O anche

$routeProvider
  .state('userpanel',
    {
      ...
      permissions: {
        except: ['not-logged-in']
      }
    });

È nuovo di zecca ma vale la pena dare un'occhiata!

https://github.com/Narzerus/angular-permission


2
cosa mi impedisce di modificare la sorgente in fase di esecuzione e di rimuovere il tuo "admin" || 'dio' e continuando?
Pogrindis,

12
Spero che tutte le richieste di dati che richiedono l'autorizzazione vengano verificate anche sul server.
Ben Ripley,

24
Questo non è pensato per la sicurezza, l'autorizzazione sul lato client non lo è mai perché puoi sempre cambiare i valori. È anche possibile intercettare le risposte dal lato server e valutarle come "autorizzate". Il punto delle autorizzazioni / autorizzazioni nel lato client è quello di evitare che l'utente faccia cose proibite per scopi dell'utente. Ad esempio, se si sta gestendo un'azione di solo amministratore, anche se l'utente inganna maliziosamente il client per consentire l'invio di una richiesta limitata al server, il server restituirà comunque una risposta 401. Questo è ovviamente sempre responsabilità dell'implementazione dell'API @BenRipley
Rafael Vidaurre,

3
Ottima risposta alla domanda Rafael. Proteggi sempre l'API perché il front-end è la cosa più ingegnerizzabile e spoofable che c'è quasi.
Frankie Loscavio,

1
Questo problema con la storia è risolto da un po 'di tempo ormai @Bohdan. Puoi usarlo tranquillamente anche con extra di Ui-router.
masterspambot,

16

Volevo condividere un'altra soluzione lavorando con il router UI 1.0.0.X

Come forse saprai, stateChangeStart e stateChangeSuccess sono ora obsoleti. https://github.com/angular-ui/ui-router/issues/2655

Invece dovresti usare $ transitions http://angular-ui.github.io/ui-router/1.0.0-alpha.1/interfaces/transition.ihookregistry.html

Ecco come l'ho raggiunto:

Per prima cosa ho e AuthService con alcune utili funzioni

angular.module('myApp')

        .factory('AuthService',
                ['$http', '$cookies', '$rootScope',
                    function ($http, $cookies, $rootScope) {
                        var service = {};

                        // Authenticates throug a rest service
                        service.authenticate = function (username, password, callback) {

                            $http.post('api/login', {username: username, password: password})
                                    .success(function (response) {
                                        callback(response);
                                    });
                        };

                        // Creates a cookie and set the Authorization header
                        service.setCredentials = function (response) {
                            $rootScope.globals = response.token;

                            $http.defaults.headers.common['Authorization'] = 'Bearer ' + response.token;
                            $cookies.put('globals', $rootScope.globals);
                        };

                        // Checks if it's authenticated
                        service.isAuthenticated = function() {
                            return !($cookies.get('globals') === undefined);
                        };

                        // Clear credentials when logout
                        service.clearCredentials = function () {
                            $rootScope.globals = undefined;
                            $cookies.remove('globals');
                            $http.defaults.headers.common.Authorization = 'Bearer ';
                        };

                        return service;
                    }]);

Quindi ho questa configurazione:

angular.module('myApp', [
    'ui.router',
    'ngCookies'
])
        .config(['$stateProvider', '$urlRouterProvider',
            function ($stateProvider, $urlRouterProvider) {
                $urlRouterProvider.otherwise('/resumen');
                $stateProvider
                        .state("dashboard", {
                            url: "/dashboard",
                            templateUrl: "partials/dashboard.html",
                            controller: "dashCtrl",
                            data: {
                                authRequired: true
                            }
                        })
                        .state("login", {
                            url: "/login",
                            templateUrl: "partials/login.html",
                            controller: "loginController"
                        })
            }])

        .run(['$rootScope', '$transitions', '$state', '$cookies', '$http', 'AuthService',
            function ($rootScope, $transitions, $state, $cookies, $http, AuthService) {

                // keep user logged in after page refresh
                $rootScope.globals = $cookies.get('globals') || {};
                $http.defaults.headers.common['Authorization'] = 'Bearer ' + $rootScope.globals;

                $transitions.onStart({
                    to: function (state) {
                        return state.data != null && state.data.authRequired === true;
                    }
                }, function () {
                    if (!AuthService.isAuthenticated()) {
                        return $state.target("login");
                    }
                });
            }]);

Puoi vedere che io uso

data: {
   authRequired: true
}

per contrassegnare lo stato accessibile solo se autenticato.

quindi, sul .run utilizzo le transizioni per verificare lo stato autorizzato

$transitions.onStart({
    to: function (state) {
        return state.data != null && state.data.authRequired === true;
    }
}, function () {
    if (!AuthService.isAuthenticated()) {
        return $state.target("login");
    }
});

Costruisco questo esempio usando del codice trovato nella documentazione di $ transitions. Sono abbastanza nuovo con il router dell'interfaccia utente ma funziona.

Spero che possa aiutare chiunque.


Questo è ottimo per coloro che utilizzano il router più recente. Grazie!
mtro,

5

Ecco come siamo usciti dall'infinito ciclo di routing e ancora utilizzati al $state.goposto di$location.path

if('401' !== toState.name) {
  if (principal.isIdentityResolved()) authorization.authorize();
}

1
Qualcuno potrebbe sapere perché quando si utilizza la risposta / impostazione accettata descritta sopra la barra degli indirizzi non viene più visualizzato l'URL e tutti i frammenti e i parametri della stringa di query? Da quando è stato implementato, la barra degli indirizzi non consente più di aggiungere segnalibri alla nostra app.
Frankie Loscavio,

1
Questo non dovrebbe essere un commento su una delle risposte esistenti? Perché non esiste un codice simile in OP e non è nemmeno chiaro a quale risposta / a quale codice si riferisca
TJ

3

Ho un'altra soluzione: quella soluzione funziona perfettamente quando hai solo contenuti che vuoi mostrare quando sei loggato. Definisci una regola in cui controlli se hai effettuato l'accesso e non il percorso delle rotte della whitelist.

$urlRouterProvider.rule(function ($injector, $location) {
   var UserService = $injector.get('UserService');
   var path = $location.path(), normalized = path.toLowerCase();

   if (!UserService.isLoggedIn() && path.indexOf('login') === -1) {
     $location.path('/login/signin');
   }
});

Nel mio esempio chiedo se non ho effettuato l'accesso e il percorso corrente che voglio instradare non fa parte di `/ login ', perché i miei percorsi nella whitelist sono i seguenti

/login/signup // registering new user
/login/signin // login to app

quindi ho accesso immediato a questi due percorsi e ogni altro percorso verrà controllato se sei online.

Ecco il mio intero file di routing per il modulo di login

export default (
  $stateProvider,
  $locationProvider,
  $urlRouterProvider
) => {

  $stateProvider.state('login', {
    parent: 'app',
    url: '/login',
    abstract: true,
    template: '<ui-view></ui-view>'
  })

  $stateProvider.state('signin', {
    parent: 'login',
    url: '/signin',
    template: '<login-signin-directive></login-signin-directive>'
  });

  $stateProvider.state('lock', {
    parent: 'login',
    url: '/lock',
    template: '<login-lock-directive></login-lock-directive>'
  });

  $stateProvider.state('signup', {
    parent: 'login',
    url: '/signup',
    template: '<login-signup-directive></login-signup-directive>'
  });

  $urlRouterProvider.rule(function ($injector, $location) {
    var UserService = $injector.get('UserService');
    var path = $location.path();

    if (!UserService.isLoggedIn() && path.indexOf('login') === -1) {
         $location.path('/login/signin');
    }
  });

  $urlRouterProvider.otherwise('/error/not-found');
}

() => { /* code */ } è la sintassi ES6, utilizzare invece function() { /* code */ }


3

Usa $ http Interceptor

Usando un intercettore $ http puoi inviare le intestazioni al back-end o viceversa e fare i tuoi controlli in quel modo.

Grande articolo sugli intercettori $ http

Esempio:

$httpProvider.interceptors.push(function ($q) {
        return {
            'response': function (response) {

                // TODO Create check for user authentication. With every request send "headers" or do some other check
                return response;
            },
            'responseError': function (reject) {

                // Forbidden
                if(reject.status == 403) {
                    console.log('This page is forbidden.');
                    window.location = '/';
                // Unauthorized
                } else if(reject.status == 401) {
                    console.log("You're not authorized to view this page.");
                    window.location = '/';
                }

                return $q.reject(reject);
            }
        };
    });

Inseriscilo nella tua funzione .config o .run.


2

Per prima cosa avrai bisogno di un servizio che puoi iniettare nei tuoi controller che abbia qualche idea dello stato di autenticazione dell'app. I dettagli di autenticazione persistenti con l'archiviazione locale sono un modo decente per affrontarlo.

Successivamente, dovrai verificare lo stato dell'autent prima che cambi lo stato. Poiché la tua app ha alcune pagine che devono essere autenticate e altre che non lo sono, crea un percorso principale che controlla l'autent e fai in modo che tutte le altre pagine che richiedono lo stesso siano figlio di quel genitore.

Infine, avrai bisogno di un modo per sapere se l'utente attualmente connesso può eseguire determinate operazioni. Ciò può essere ottenuto aggiungendo una funzione "can" al servizio di autenticazione. Può accettare due parametri: - azione - obbligatorio - (es. 'Manage_dashboards' o 'create_new_dashboard') - oggetto - opzionale - oggetto su cui operare. Ad esempio, se si disponeva di un oggetto dashboard, è possibile verificare se dashboard.ownerId === loggInUser.id. (Naturalmente, le informazioni trasmesse dal client non dovrebbero mai essere affidabili e dovresti sempre verificarle sul server prima di scriverle nel tuo database).

angular.module('myApp', ['ngStorage']).config([
   '$stateProvider',
function(
   $stateProvider
) {
   $stateProvider
     .state('home', {...}) //not authed
     .state('sign-up', {...}) //not authed
     .state('login', {...}) //not authed
     .state('authed', {...}) //authed, make all authed states children
     .state('authed.dashboard', {...})
}])
.service('context', [
   '$localStorage',
function(
   $localStorage
) {
   var _user = $localStorage.get('user');
   return {
      getUser: function() {
         return _user;
      },
      authed: function() {
         return (_user !== null);
      },
      // server should return some kind of token so the app 
      // can continue to load authenticated content without having to
      // re-authenticate each time
      login: function() {
         return $http.post('/login.json').then(function(reply) {
            if (reply.authenticated === true) {
               $localStorage.set(_userKey, reply.user);
            }
         });
      },
      // this request should expire that token, rendering it useless
      // for requests outside of this session
      logout: function() {
         return $http.post('logout.json').then(function(reply) {
            if (reply.authenticated === true) {
               $localStorage.set(_userKey, reply.user);
            }
         });
      },
      can: function(action, object) {
         if (!this.authed()) {
            return false;
         }

         var user = this.getUser();

         if (user && user.type === 'admin') {
             return true;
         }

         switch(action) {
            case 'manage_dashboards':
               return (user.type === 'manager');
         }

         return false;


      }
   }
}])
.controller('AuthCtrl', [
   'context', 
   '$scope', 
function(
   context, 
   $scope
) {
   $scope.$root.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
      //only require auth if we're moving to another authed page
      if (toState && toState.name.indexOf('authed') > -1) {
         requireAuth();
      }
   });

   function requireAuth() {
      if (!context.authed()) {
         $state.go('login');
      }
   }
}]

** DISCLAIMER: il codice sopra è pseudo-codice e non ha garanzie **

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.