Ho creato un repository GitHub riassumendo fondamentalmente questo articolo: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
ng-login Github repo
Plunker
Cercherò di spiegare il più bene possibile, spero di aiutare alcuni di voi là fuori:
(1) app.js: creazione di costanti di autenticazione sulla definizione dell'app
var loginApp = angular.module('loginApp', ['ui.router', 'ui.bootstrap'])
/*Constants regarding user login defined here*/
.constant('USER_ROLES', {
all : '*',
admin : 'admin',
editor : 'editor',
guest : 'guest'
}).constant('AUTH_EVENTS', {
loginSuccess : 'auth-login-success',
loginFailed : 'auth-login-failed',
logoutSuccess : 'auth-logout-success',
sessionTimeout : 'auth-session-timeout',
notAuthenticated : 'auth-not-authenticated',
notAuthorized : 'auth-not-authorized'
})
(2) Servizio di autenticazione : tutte le seguenti funzioni sono implementate nel servizio auth.js. Il servizio $ http viene utilizzato per comunicare con il server per le procedure di autenticazione. Contiene anche funzioni sull'autorizzazione, ovvero se l'utente è autorizzato a eseguire una determinata azione.
angular.module('loginApp')
.factory('Auth', [ '$http', '$rootScope', '$window', 'Session', 'AUTH_EVENTS',
function($http, $rootScope, $window, Session, AUTH_EVENTS) {
authService.login() = [...]
authService.isAuthenticated() = [...]
authService.isAuthorized() = [...]
authService.logout() = [...]
return authService;
} ]);
(3) Sessione: un singleton per conservare i dati dell'utente. L'implementazione qui dipende da te.
angular.module('loginApp').service('Session', function($rootScope, USER_ROLES) {
this.create = function(user) {
this.user = user;
this.userRole = user.userRole;
};
this.destroy = function() {
this.user = null;
this.userRole = null;
};
return this;
});
(4) Controller principale: considera questa come la funzione "principale" della tua applicazione, tutti i controller ereditano da questo controller ed è la spina dorsale dell'autenticazione di questa app.
<body ng-controller="ParentController">
[...]
</body>
(5) Controllo di accesso: per negare l'accesso su determinate rotte è necessario implementare 2 passaggi:
a) Aggiungere i dati dei ruoli autorizzati ad accedere a ciascuna route, sul servizio $ stateProvider del router ui come si può vedere di seguito (lo stesso può funzionare per ngRoute).
.config(function ($stateProvider, USER_ROLES) {
$stateProvider.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard/index.html',
data: {
authorizedRoles: [USER_ROLES.admin, USER_ROLES.editor]
}
});
})
b) In $ rootScope. $ on ('$ stateChangeStart') aggiungere la funzione per impedire il cambiamento di stato se l'utente non è autorizzato.
$rootScope.$on('$stateChangeStart', function (event, next) {
var authorizedRoles = next.data.authorizedRoles;
if (!Auth.isAuthorized(authorizedRoles)) {
event.preventDefault();
if (Auth.isAuthenticated()) {
// user is not allowed
$rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
} else {
// user is not logged in
$rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
}
}
});
(6) Interceptor di autenticazione: è implementato, ma non può essere verificato sull'ambito di questo codice. Dopo ogni richiesta $ http, questo intercettore controlla il codice di stato, se viene restituito uno dei seguenti, quindi trasmette un evento per costringere l'utente ad accedere nuovamente.
angular.module('loginApp')
.factory('AuthInterceptor', [ '$rootScope', '$q', 'Session', 'AUTH_EVENTS',
function($rootScope, $q, Session, AUTH_EVENTS) {
return {
responseError : function(response) {
$rootScope.$broadcast({
401 : AUTH_EVENTS.notAuthenticated,
403 : AUTH_EVENTS.notAuthorized,
419 : AUTH_EVENTS.sessionTimeout,
440 : AUTH_EVENTS.sessionTimeout
}[response.status], response);
return $q.reject(response);
}
};
} ]);
PS Un bug con la compilazione automatica dei dati del modulo come indicato nel primo articolo può essere facilmente evitato aggiungendo la direttiva inclusa in directives.js.
PS2 Questo codice può essere facilmente modificato dall'utente, per consentire la visualizzazione di percorsi diversi o per visualizzare contenuti che non dovevano essere visualizzati. La logica DEVE essere implementata lato server, questo è solo un modo per mostrare le cose correttamente sulla tua ng-app.