Estou escrevendo um pequeno aplicativo AngularJS que possui uma visualização de login e uma visualização principal, configuradas da seguinte forma:
$routeProvider
.when('/main' , {templateUrl: 'partials/main.html', controller: MainController})
.when('/login', {templateUrl: 'partials/login.html', controller: LoginController})
.otherwise({redirectTo: '/login'});
Meu LoginController verifica a combinação user / pass e define uma propriedade no $ rootScope refletindo isso:
function LoginController($scope, $location, $rootScope) {
$scope.attemptLogin = function() {
if ( $scope.username == $scope.password ) { // test
$rootScope.loggedUser = $scope.username;
$location.path( "/main" );
} else {
$scope.loginError = "Invalid user/pass.";
}
}
Tudo funciona, mas se eu acessar, http://localhost/#/main
acabo ignorando a tela de login. Eu queria escrever algo como "sempre que a rota mudar, se $ rootScope.loggedUser for nulo, em seguida, redirecione para / login"
...
... esperar. Posso ouvir as alterações de rota de alguma forma? Vou postar esta pergunta de qualquer maneira e continuar procurando.
Respostas:
Depois de mergulhar na documentação e no código fonte, acho que consegui funcionar. Talvez isso seja útil para outra pessoa?
Adicionei o seguinte à configuração do meu módulo:
A única coisa que parece estranha é que eu tive que testar o nome parcial (
login.html
) porque o "próximo" objeto Route não tinha um URL ou outra coisa. Talvez haja uma maneira melhor?fonte
Aqui está, talvez, uma solução mais elegante e flexível com a propriedade de configuração 'resolver' e 'promessas', permitindo o eventual carregamento de dados nas regras de roteamento e roteamento, dependendo dos dados.
Você especifica uma função em 'resolve' na configuração de roteamento e, na função carregar e verificar dados, faz todos os redirecionamentos. Se você precisar carregar dados, retornará uma promessa, se precisar redirecionar - rejeite a promessa antes disso. Todos os detalhes podem ser encontrados nas páginas de documentação $ routerProvider e $ q .
Para pessoas que falam russo, há um post no habr " Вариант условного раутинга no AngularJS ".
fonte
ui.router
for usado, use em$stateProvider
vez de$routeProvider
.Eu tenho tentado fazer o mesmo. Surgiu outra solução mais simples depois de trabalhar com um colega. Eu tenho um relógio configurado
$location.path()
. Isso faz o truque. Estou começando a aprender o AngularJS e acho que isso é mais limpo e legível.fonte
Uma maneira diferente de implementar o redirecionamento de logon é usar eventos e interceptores, conforme descrito aqui . O artigo descreve algumas vantagens adicionais, como detectar quando um logon é necessário, enfileirar as solicitações e reproduzi-las quando o logon for bem-sucedido.
Você pode experimentar uma demonstração funcional aqui e ver a fonte da demonstração aqui .
fonte
1. Defina o usuário atual global.
No seu serviço de autenticação, defina o usuário atualmente autenticado no escopo raiz.
2. Defina a função de autenticação em cada rota protegida.
3. Verifique a autenticação em cada alteração de rota.
Como alternativa, você pode definir permissões no objeto de usuário e atribuir uma permissão a cada rota, depois verifique a permissão no retorno de chamada do evento.
fonte
if (!user && !next.$$route.public)
next.$$route
me explicar ? Não encontro nada nos documentos angulares que descrevem os argumentos atribuídos a um$routeChangeStart
evento, mas assumonext
ecurr
são algum tipo de objeto de localização? O$$route
bit é difícil de pesquisar.$$route
propriedade é uma variável privada da Angular. Você não deve confiar nisso, consulte, por exemplo: stackoverflow.com/a/19338518/1132101 - se o fizer, seu código poderá ser interrompido quando o Angular for alterado.$route.routes
para construir uma lista (como na resposta de @ thataustin): obter o caminho para o local comnext.originalPath
e usar isso para index$route.routes
:var auth = $route.routes[next.originalPath]
.Aqui está como eu fiz isso, caso ajude alguém:
Na configuração, defino um
publicAccess
atributo nas poucas rotas que quero abrir ao público (como login ou registro):em um bloco de execução, defino um ouvinte no
$routeChangeStart
evento que será redirecionado, a'/login'
menos que o usuário tenha acesso ou a rota seja publicamente acessível:Obviamente, você pode alterar a condição de
isLoggedIn
para qualquer outra coisa ... apenas mostrando outra maneira de fazê-lo.fonte
nextLoc.$$route.publicAccess
btw.$route.routes[nextLoc.originalPath]
, que não usa uma variável privada.nextLoc && nextLoc.publicAccess
!Estou fazendo isso usando interceptores. Eu criei um arquivo de biblioteca que pode ser adicionado ao arquivo index.html. Dessa forma, você terá o tratamento global de erros para suas chamadas de serviço de descanso e não precisará se preocupar com todos os erros individualmente. Mais abaixo, colei também minha biblioteca de login de autenticação básica. Lá você pode ver que eu também verifico o erro 401 e redireciono para um local diferente. Consulte lib / ea-basic-auth-login.js
lib / http-error-handling.js
css / http-error-handling.css
index.html
lib / ea-basic-auth-login.js
Quase o mesmo pode ser feito para o login. Aqui você tem a resposta para o redirecionamento ($ location.path ("/ login")).
fonte
No seu arquivo app.js:
fonte
É possível redirecionar para outra exibição com o angular-ui-router . Para este fim, temos o método
$state.go("target_view")
. Por exemplo:fonte
Se você não deseja usar o angular-ui-router, mas gostaria de ter seus controladores preguiçosamente carregados via RequireJS, existem alguns problemas com o evento
$routeChangeStart
ao usar seus controladores como módulos RequireJS (carregamento lento).Você não pode ter certeza de que o controlador será carregado antes de
$routeChangeStart
ser acionado - na verdade, ele não será carregado. Isso significa que você não pode acessar propriedades danext
rota comolocals
ou$$route
porque elas ainda não estão configuradas.Exemplo:
Isso significa que você não pode verificar os direitos de acesso lá.
Solução:
Como o carregamento do controlador é feito por meio de determinação, você pode fazer o mesmo com sua verificação de controle de acesso:
Observe aqui que, em vez de usar o evento
$routeChangeStart
, estou usando$routeChangeError
fonte
fonte