He creado un repositorio de github que resume este artículo básicamente: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
ng-login repositorio de Github
Plunker
Intentaré explicarlo lo mejor posible, espero ayudar a algunos de ustedes:
(1) app.js: creación de constantes de autenticación en la definición de la aplicación
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) Servicio de autenticación: todas las funciones siguientes se implementan en el servicio de autenticación. El servicio $ http se utiliza para comunicarse con el servidor para los procedimientos de autenticación. También contiene funciones de autorización, es decir, si el usuario puede realizar una determinada acción.
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) Sesión: Un singleton para mantener los datos del usuario. La implementación aquí depende de ti.
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) Controlador principal: considere esto como la función "principal" de su aplicación, todos los controladores heredan de este controlador y es la columna vertebral de la autenticación de esta aplicación.
<body ng-controller="ParentController">
[...]
</body>
(5) Control de acceso: Para denegar el acceso en determinadas rutas, se deben implementar 2 pasos:
a) Agregue datos de los roles permitidos para acceder a cada ruta, en el servicio $ stateProvider del enrutador ui como se puede ver a continuación (lo mismo puede funcionar para ngRoute).
.config(function ($stateProvider, USER_ROLES) {
$stateProvider.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard/index.html',
data: {
authorizedRoles: [USER_ROLES.admin, USER_ROLES.editor]
}
});
})
b) En $ rootScope. $ on ('$ stateChangeStart') agregue la función para evitar el cambio de estado si el usuario no está autorizado.
$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 de autenticación: esto está implementado, pero no se puede verificar en el alcance de este código. Después de cada solicitud $ http, este interceptor comprueba el código de estado, si se devuelve uno de los siguientes, emite un evento para obligar al usuario a iniciar sesión nuevamente.
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);
}
};
} ]);
PD: Un error con el autocompletado de datos del formulario como se indica en el primer artículo puede evitarse fácilmente agregando la directiva que se incluye en directives.js.
PS2 El usuario puede modificar este código fácilmente para permitir que se vean diferentes rutas o mostrar contenido que no estaba destinado a mostrarse. La lógica DEBE implementarse en el lado del servidor, esta es solo una forma de mostrar las cosas correctamente en su ng-app.