Autenticação de login do roteador ui do AngularJS


376

Eu sou novo no AngularJS e estou um pouco confuso sobre como posso usar o "ui-router" angular no seguinte cenário:

Estou construindo um aplicativo da web que consiste em duas seções. A primeira seção é a página inicial com suas visualizações de login e inscrição e a segunda seção é o painel (após o login bem-sucedido).

Eu criei uma index.htmlseção para a página inicial com seu aplicativo angular e ui-routerconfiguração para manipular /logine/signup exibir, e há outro arquivo dashboard.htmlpara a seção do painel com seu aplicativo e ui-routerconfiguração para manipular muitas visualizações secundárias.

Agora terminei a seção do painel e não sei como combinar as duas seções com seus aplicativos angulares diferentes. Como eu poderia dizer ao aplicativo inicial para redirecionar para o aplicativo do painel?


11
Você pode compartilhar algum código conosco?
Chancho 20/03/2014

6
@ Chancho Eu acho que não se trata de código, realmente não sei qual código devo compartilhar.
Ahmed Hashem

Sim, por favor compartilhar o código, pergunta muito genérica ...
Alireza

Respostas:


607

Estou no processo de criar uma demonstração melhor, além de limpar alguns desses serviços em um módulo utilizável, mas aqui está o que eu propus. Este é um processo complexo para contornar algumas advertências, então fique aí. Você precisará dividir isso em vários pedaços.

Dê uma olhada neste plunk .

Primeiro, você precisa de um serviço para armazenar a identidade do usuário. Eu chamo isso principal. Ele pode ser verificado para ver se o usuário está logado e, mediante solicitação, ele pode resolver um objeto que representa as informações essenciais sobre a identidade do usuário. Pode ser o que você precisar, mas o essencial seria um nome para exibição, um nome de usuário, possivelmente um email e as funções às quais um usuário pertence (se isso se aplica ao seu aplicativo). O Principal também possui métodos para fazer verificações de função.

.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;
      }
    };
  }
])

Segundo, você precisa de um serviço que verifique o estado em que o usuário deseja ir, verifique se está logado (se necessário; não necessário para entrar, redefinição de senha etc.) e faça uma verificação de função (se seu aplicativo precisa disso). Se eles não estiverem autenticados, envie-os para a página de entrada. Se eles estiverem autenticados, mas falharem na verificação de uma função, envie-os para uma página de acesso negado. Eu chamo esse serviço 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');
              }
            }
          });
      }
    };
  }
])

Agora tudo que você precisa fazer é ouvir em ui-router's $stateChangeStart. Isso permite examinar o estado atual, o estado para o qual eles desejam ir e inserir sua verificação de autorização. Se falhar, você pode cancelar a transição da rota ou mudar para uma rota diferente.

.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();
      });
    }
  ]);

A parte complicada de rastrear a identidade de um usuário é procurar se você já se autenticou (por exemplo, você está visitando a página após uma sessão anterior e salvou um token de autenticação em um cookie, ou talvez você tenha atualizado uma página ou caiu para um URL a partir de um link). Por causa da maneira como ui-routerfunciona, você precisa resolver sua identidade uma vez, antes de verificar sua autenticação. Você pode fazer isso usando a resolveopção na sua configuração de estado. Eu tenho um estado pai para o site que todos os estados herdam, o que força o principal a ser resolvido antes que qualquer outra coisa aconteça.

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

Há outro problema aqui ... resolvesó é chamado uma vez. Quando sua promessa de pesquisa de identidade for concluída, ela não executará o delegado de resolução novamente. Portanto, precisamos fazer suas verificações de autenticação em dois locais: uma vez de acordo com a promessa de identidade que está sendo resolvida resolve, que abrange a primeira vez que o aplicativo é carregado e outra$stateChangeStart se a resolução foi concluída, que abrange qualquer momento em que você navega pelos estados.

OK, então o que fizemos até agora?

  1. Verificamos quando o aplicativo carrega se o usuário está logado.
  2. Nós rastreamos informações sobre o usuário conectado.
  3. Nós os redirecionamos para entrar no estado para estados que exigem que o usuário esteja logado.
  4. Nós os redirecionamos para um estado de acesso negado se eles não tiverem autorização para acessá-lo.
  5. Temos um mecanismo para redirecionar os usuários de volta ao estado original que eles solicitaram, se precisávamos deles para fazer login.
  6. Podemos desconectar um usuário (precisa ser conectado em conjunto com qualquer código de cliente ou servidor que gerencia seu tíquete de autenticação).
  7. Nós não precisa enviar os usuários de volta para a página de login cada vez que recarregar seu navegador ou cair em um link.

Para onde vamos daqui? Bem, você pode organizar seus estados em regiões que necessitam de sinal. Você pode exigir que os usuários autenticados / autorizados pela adição datacom rolesa estes estados (ou um pai deles, se você quiser usar a herança). Aqui, restringimos um recurso aos administradores:

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

Agora você pode controlar estado por estado o que os usuários podem acessar uma rota. Alguma outra preocupação? Talvez variar apenas parte de uma visualização com base em se eles estão ou não conectados? Sem problemas. Use principal.isAuthenticated()ou mesmo principal.isInRole()com qualquer uma das várias maneiras pelas quais você pode exibir condicionalmente um modelo ou elemento.

Primeiro, injete principalem um controlador ou o que seja, e cole-o no escopo para que você possa usá-lo facilmente em sua visão:

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

Mostrar ou ocultar um elemento:

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

Etc., etc., etc. De qualquer forma, em seu aplicativo de exemplo, você teria um estado para a página inicial que permitiria a exibição de usuários não autenticados. Eles podem ter links para os estados de entrada ou inscrição ou ter esses formulários incorporados nessa página. O que mais lhe convier.

Todas as páginas do painel podem herdar de um estado que exige que os usuários estejam conectados e, digamos, sejam Usermembros da função. Todo o material de autorização que discutimos fluiria a partir daí.


28
Obrigado, isso realmente me ajudou a obter meu próprio código. Além disso, se você receber um loop de roteamento infinito (bug no roteador da interface do usuário), tente em $location.pathvez de $state.go.
precisa saber é o seguinte

2
Esta é uma ótima resposta e me ajudou muito. Quando defino user = principal no meu controlador e tento chamar say user.identity (). Name na minha visualização para obter o nome de usuário atualmente conectado, apenas pareço obter o objeto de promessa {then: fn, catch: fn, finalmente :} retornou e não o objeto _identity real. Se eu usar user.identity.then (fn (user)), posso obter o objeto de usuário, mas isso parece ter muito código para a exibição. Estou perdendo alguma coisa?
Mark

4
@ Ir1sh Gostaria de resolver a identidade primeiro no controlador e atribuí-la $scope.userna sua thenfunção. Você ainda pode fazer referência userem seus pontos de vista; quando for resolvido, a exibição será atualizada.
moribvndvs

2
@HackedByChinese Acho que sua demo não está mais funcionando.
Blowsie

7
@jvannistelrooy Eu tive problemas com go () para, mas depois de colocá-lo dentro do e depois de chamar uma função noop como esta $q.when(angular.noop).then(function(){$state.go('myState'), tudo funciona como esperado. Se eu ligar $state.goenquanto outra transição de estado não estiver concluída, ela não funcionará (acho que é por isso que não funcionará).
Sebastian

120

As soluções postadas até agora são desnecessariamente complicadas, na minha opinião. Existe uma maneira mais simples. A documentação doui-router diz ouvir $locationChangeSuccesse usar$urlRouter.sync() para verificar uma transição de estado, interrompê-la ou retomar. Mas mesmo isso realmente não funciona.

No entanto, aqui estão duas alternativas simples. Escolha um:

Solução 1: ouvindo $locationChangeSuccess

Você pode ouvir $locationChangeSuccesse executar alguma lógica, mesmo lógica assíncrona lá. Com base nessa lógica, você pode deixar a função retornar indefinida, o que fará com que a transição de estado continue normalmente, ou você pode fazê-lo $state.go('logInPage'), se o usuário precisar ser autenticado. Aqui está um exemplo:

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')
      })
  })
})

Lembre-se de que isso não impede que o estado de destino seja carregado, mas redireciona para a página de logon se o usuário não for autorizado. Tudo bem, já que a proteção real está no servidor.

Solução 2: usando estado resolve

Nesta solução, você usa o ui-routerrecurso de resolução .

Você basicamente rejeita a promessa resolvese o usuário não estiver autenticado e, em seguida, redireciona-o para a página de logon.

Aqui está como vai:

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()
      }
    }
  }
)

Diferentemente da primeira solução, essa solução realmente impede que o estado de destino seja carregado.


6
@FredLackey dizem usuário não autenticado é state A. Eles clicam em um link para acessar, protected state Bmas você deseja redirecioná-los para logInPage. Se não houver $timeout, ui-routersimplesmente interromperá todas as transições de estado, para que o usuário fique preso state A. O $timeoutpermite ui-routerimpedir primeiro a transição inicial para, protected state Bporque a resolução foi rejeitada e, depois disso, é redirecionada para logInPage.
MK-Safi-

Onde a authenticatefunção é realmente chamada?
CodyBugstein

A authenticatefunção @Imray é passada como um parâmetro para ui-router. Você não precisa se chamar. ui-routerchama.
MK Safi

Por que você está usando '$ locationChangeSuccess' em vez de '$ stateChangeStart'?
Draex_ 8/08/15

@ PeterDraexDräxler Eu estava principalmente seguindo a documentação. Você notou alguma diferença usando $stateChangeStart?
MK Safi

42

A solução mais fácil é usar $stateChangeStarte event.preventDefault()cancelar a alteração de estado quando o usuário não estiver autenticado e redirecioná-lo para o estado de autenticação que é a página de logon.

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
Eu não acho que isso funcionará se User.authenticaded () for uma chamada assíncrona. Esse é o Santo Graal que todos buscam. Por exemplo, se todos os estados, exceto "login", estiverem protegidos, desejo confirmar que o usuário ainda está autenticado antes de carregar qualquer estado. O uso de resolves é uma porcaria porque eles são resolvidos apenas uma vez e, para impedir que estados filhos sejam carregados, é necessário injetar a resolução em TODAS AS CRIANÇAS .
23415 Jason

autenticado não é uma chamada assíncrona no meu caso: `this.authenticaded = function () {if (this.currentAccountID! == null) {return true; } retorna falso; }; `
sebest 13/11/2015

De acordo com: stackoverflow.com/a/38374313/849829 , 'run' fica muito acima dos 'serviços e, portanto, dos problemas. Verificar o armazenamento local para o status autenticado parece ser uma boa abordagem.
Deepak Thomas

22

Eu acho que você precisa de um serviceque lide com o processo de autenticação (e seu armazenamento).

Neste serviço, você precisará de alguns métodos básicos:

  • isAuthenticated()
  • login()
  • logout()
  • etc ...

Este serviço deve ser injetado nos controladores de cada módulo:

  • Na seção do painel, use este serviço para verificar se o usuário está autenticado (service.isAuthenticated() método). caso contrário, redirecione para / login
  • Na sua seção de login, basta usar os dados do formulário para autenticar o usuário através do seu service.login()método

Um exemplo bom e robusto para esse comportamento é o aplicativo angular do projeto e, especificamente, seu módulo de segurança, baseado no incrível módulo HTTP Auth Interceptor

Espero que isto ajude


21

Criei este módulo para ajudar a tornar esse processo fácil

Você pode fazer coisas como:

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

Ou também

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

É novo, mas vale a pena conferir!

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


2
o que me impede de editar a fonte em tempo de execução e remover o seu 'admin' || 'deus' e continuando?
Pogrindis

12
Espero que qualquer solicitação de dados que exija autorização também esteja sendo verificada no servidor.
Ben Ripley

24
Isso não se destina à segurança, a autorização do cliente nunca é, pois você sempre pode alterar os valores. Você pode até interceptar respostas do lado do servidor e avaliá-las como "autorizadas". O objetivo das permissões / autorizações no lado do cliente é evitar que o usuário faça coisas proibidas para fins de ux. Por exemplo, se você estiver lidando com uma ação apenas de administrador, mesmo que o usuário engane maliciosamente o cliente para permitir o envio de uma solicitação restrita ao servidor, o servidor ainda retornará uma resposta 401. Isto é de @BenRipley claro, sempre responsabilidade do api sendo implementado de fato
Rafael Vidaurre

3
Ótima resposta à pergunta Rafael. Sempre proteja as APIs porque o front-end é a coisa mais reversível e engenheirável que existe.
Frankie Loscavio

11
Este problema com a história está resolvido há um bom tempo agora @Bohdan. Você pode usá-lo com segurança, mesmo com extras do ui-router.
masterspambot

16

Eu queria compartilhar outra solução trabalhando com o ui router 1.0.0.X

Como você deve saber, stateChangeStart e stateChangeSuccess agora estão obsoletos. https://github.com/angular-ui/ui-router/issues/2655

Em vez disso, você deve usar $ transitions http://angular-ui.github.io/ui-router/1.0.0-alpha.1/interfaces/transition.ihookregistry.html

Foi assim que consegui:

Primeiro eu tenho e AuthService com algumas funções úteis

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;
                    }]);

Então eu tenho esta configuração:

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");
                    }
                });
            }]);

Você pode ver que eu uso

data: {
   authRequired: true
}

para marcar o estado apenas acessível se estiver autenticado.

então, no .run , uso as transições para verificar o estado autenticado

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

Eu construo este exemplo usando algum código encontrado na documentação de $ transitions. Eu sou muito novo com o roteador da interface do usuário, mas funciona.

Espero que possa ajudar alguém.


Isso é ótimo para quem usa o roteador mais recente. Obrigado!
Mtro

5

Aqui está como saímos do loop de roteamento infinito e ainda usamos em $state.govez de$location.path

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

11
Alguém saberia por que, ao usar a resposta / configuração aceita descrita acima, a barra de endereço não exibe mais o URL e todos os fragmentos e parâmetros de string de consulta? Desde a implementação, a barra de endereço não permite mais que nosso aplicativo seja marcado como favorito.
Frankie Loscavio

11
Isso não deveria ser um comentário sobre uma das respostas existentes? Como não existe esse código no OP e nem sequer é claro a qual resposta / a qual código isso se refere
TJ

3

Eu tenho outra solução: essa solução funciona perfeitamente quando você tem apenas o conteúdo que deseja mostrar quando está conectado. Defina uma regra em que você verifica se está conectado e não é o caminho das rotas da lista de permissões.

$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');
   }
});

No meu exemplo, pergunto se não estou logado e a rota atual que desejo encaminhar não faz parte de `/ login ', porque minhas rotas da lista de permissões são as seguintes

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

então eu tenho acesso instantâneo a essas duas rotas e todas as outras rotas serão verificadas se você estiver online.

Aqui está meu arquivo de roteamento completo para o módulo de 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 */ } é a sintaxe do ES6, use em vez disso function() { /* code */ }


3

Use o $ http Interceptor

Usando um interceptor $ http, você pode enviar cabeçalhos para o Back-end ou o contrário e fazer suas verificações dessa maneira.

Ótimo artigo sobre interceptores $ http

Exemplo:

$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);
            }
        };
    });

Coloque isso na sua função .config ou .run.


2

Primeiro, você precisará de um serviço que possa injetar nos controladores com alguma idéia do estado de autenticação do aplicativo. Persistir detalhes de autenticação com armazenamento local é uma maneira decente de abordá-lo.

Em seguida, você precisará verificar o estado de autenticação antes de alterar o estado. Como seu aplicativo possui algumas páginas que precisam ser autenticadas e outras que não, crie uma rota pai que verifique a autenticação e faça com que todas as outras páginas que exigem o mesmo sejam filhas desse pai.

Por fim, você precisará de uma maneira de saber se o usuário conectado no momento pode executar determinadas operações. Isso pode ser conseguido adicionando uma função 'can' ao seu serviço de autenticação. O Can possui dois parâmetros: - ação - necessária - (ou seja, 'manage_dashboards' ou 'create_new_dashboard') - objeto - opcional - objeto em operação. Por exemplo, se você tinha um objeto de painel, convém verificar se dashboard.ownerId === logInUser.id. (Obviamente, as informações transmitidas pelo cliente nunca devem ser confiáveis ​​e você sempre deve verificar isso no servidor antes de gravá-las no banco de dados).

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');
      }
   }
}]

** AVISO LEGAL: O código acima é pseudo-código e vem sem garantias **

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.