Criei um repositório github resumindo este artigo basicamente: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
repositório Github ng-login
Plunker
Vou tentar explicar da melhor maneira possível, espero ajudar alguns de vocês aí:
(1) app.js: Criação de constantes de autenticação na definição do aplicativo
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) Serviço de autenticação: Todas as funções a seguir são implementadas no serviço auth.js. O serviço $ http é usado para se comunicar com o servidor para os procedimentos de autenticação. Também contém funções de autorização, isto é, se o usuário tem permissão para realizar uma determinada ação.
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) Sessão: Um singleton para manter os dados do usuário. A implementação aqui depende de você.
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 pai: considere isso como a função "principal" de seu aplicativo, todos os controladores herdam deste controlador e é a espinha dorsal da autenticação deste aplicativo.
<body ng-controller="ParentController">
[...]
</body>
(5) Controle de acesso: para negar o acesso em certas rotas, 2 etapas devem ser implementadas:
a) Adicione os dados das funções permitidas para acessar cada rota, no serviço $ stateProvider do roteador ui como pode ser visto abaixo (o mesmo pode funcionar para o ngRoute).
.config(function ($stateProvider, USER_ROLES) {
$stateProvider.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard/index.html',
data: {
authorizedRoles: [USER_ROLES.admin, USER_ROLES.editor]
}
});
})
b) Em $ rootScope. $ on ('$ stateChangeStart') adicione a função para evitar a mudança de estado se o usuário não estiver 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) Interceptador de autenticação: implementado, mas não pode ser verificado no escopo deste código. Após cada solicitação $ http, este interceptor verifica o código de status, se um dos itens abaixo for retornado, ele transmite um evento para forçar o usuário a efetuar login novamente.
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 Um bug com o preenchimento automático dos dados do formulário, conforme declarado no primeiro artigo, pode ser facilmente evitado adicionando-se a diretiva incluída em directives.js.
PS2 Este código pode ser facilmente ajustado pelo usuário, para permitir que diferentes rotas sejam vistas ou exibir conteúdo que não deveria ser exibido. A lógica DEVE ser implementada no lado do servidor, esta é apenas uma maneira de mostrar as coisas corretamente em seu ng-app.