$ stateChangeStart запускается до получения данных от Rest API

Я пытался сделать аутентификацию пользователя при входе в систему, я сделал сервис с именем AuthService с методом isAuthenticated в котором я делаю вызов API для перекрестной проверки входа пользователя в систему или нет (также я буду использовать роль пользователя в нем позже), а затем я вызываю эту службу в $rootScope.$on но не ждите, пока мой сервис получит данные из API, вот мой app.js

var app = angular.module('myApp', ['ngRoute', 'ui.router', 'ngAnimate', 'toaster', 'ui.bootstrap']);

app.config(['$routeProvider', '$locationProvider', '$stateProvider', '$urlRouterProvider',
function ($routeProvider, $locationProvider, $stateProvider, $urlRouterProvider) {
$stateProvider.
state('/', {
url: "/",
views: {
header: {
templateUrl: 'partials/common/header.html',
controller: 'authCtrl',
},
content: {
templateUrl: 'partials/dashboard.html',
controller: 'authCtrl',
}
},
title: 'Dashboard',
authenticate: true
})

.state('login', {
url: "/login",
views: {
content: {
templateUrl: 'partials/login.html',
controller: 'authCtrl',
}
},
title: 'Login',
authenticate: false
})

.state('dashboard', {
title: 'Dashboard',
url: "/dashboard",
views: {
header: {
templateUrl: 'partials/common/header.html',
controller: 'authCtrl',
},
content: {
templateUrl: 'partials/dashboard.html',
controller: 'authCtrl',
}
},
authenticate: true
});
$urlRouterProvider.otherwise("/");

//check browser support
if(window.history && window.history.pushState){
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
}
}])
.run(function ($rootScope, $location, $state, Data, AuthService) {
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
$rootScope.title = toState.title;
$rootScope.authenticated = false;
var userInfo = AuthService.isAuthenticated();
if (toState.authenticate && !AuthService.isAuthenticated()){
// User isn’t authenticated
$state.transitionTo("login");
event.preventDefault();
} else {
alert('here I am ='+$rootScope.authenticated);
}
});
});

Вот мой сервис

app.factory('AuthService', function ($http, Data, $rootScope) {
var authService = {};

authService.isAuthenticated = function () {
Data.get('index.php/api/authentication/is_login').then(function (results) {
if (results.uid) {
$rootScope.authenticated = true;
$rootScope.uid = results.uid;
$rootScope.name = results.name;
$rootScope.email = results.email;
return results.uid;
} else {
return false;
}
});
}
return authService;
});

Перепробовал много вещей, но пока не повезло. Пожалуйста, предложите лучший способ сделать это, я пробовал метод разрешения в ui-маршрутах, но не сработал.

Заранее спасибо.

2

Решение

Реализация, которая у вас есть, не будет работать, потому что Data.get() функция возвращает Promiseи, следовательно, является асинхронным. Из-за этого изменение маршрута будет происходить без ожидания, пока ваша служба аутентификации вернет какое-либо значение.

Чтобы решить вашу проблему, вы должны обработать эту асинхронную логику определенным образом:

app.run(function ($rootScope, $location, $state, Data, AuthService) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
/**
* If the user is heading towards a state that requires
* authentication, assume that they are not authenticated,
* and stop them! Otherwise, let them through...
*/
if (toState.authenticate) {
event.preventDefault();

if (toState.name !== fromState.name) {
// Now check whether or not they are authenticated
AuthService.isAuthenticated().then(function () {
// Yes! They're authenticated, continue
$state.go(toState.name, toParams);
}, function () {
// Nope, this user cannot view this page
alert('You cannot view this page!');
});
}
} else {
return;
}
});
}

Редактировать: Я добавил чек toState.name !== fromState.name прервать любые петли перенаправления, которые могут затем вызвать бесконечные вызовы к службе аутентификации. Это было в ответ на комментарий, сделанный оригинальным постером проблемы.

Хитрость заключается в том, чтобы предотвратить переход маршрута, по умолчанию. Затем вы сможете выполнять столько асинхронной логики, сколько пожелаете, прежде чем пользователю будет разрешено двигаться дальше.

Я бы порекомендовал добавить спиннер или загрузочное окно, чтобы предупредить пользователя о том, что вы выполняете эту проверку подлинности. Также может быть целесообразно предотвратить любые дальнейшие действия пользователя на странице, но это полностью ваше дело.

Обратите внимание, что функция AuthService.isAuthenticated() теперь возвращает PromiseДля этого вам нужно будет внести небольшие изменения в службу аутентификации. Просто оберните вашу текущую логику следующим образом:

app.factory('AuthService', function ($http, Data, $rootScope, $q) {
var authService = {};

authService.isAuthenticated = function () {
return $q(function (resolve, reject) {
Data.get('index.php/api/authentication/is_login').then(function (results) {
if (results.uid) {
$rootScope.authenticated = true;
$rootScope.uid = results.uid;
$rootScope.name = results.name;
$rootScope.email = results.email;

// Great, the user is authenticated, resolve the Promise
resolve(results.uid);
} else {
// The user does not appear to be authenticated, reject the Promise
reject();
}
});
});
};

return authService;
});

Я надеюсь, что это решит вашу проблему, обещания могут быть болезненными, но они также могут быть довольно мощным инструментом. На GitHub была хорошая ветка, обсуждающая ряд потенциальных решений этой проблемы, которые можно найти здесь: https://github.com/angular-ui/ui-router/issues/1399.


0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector