Я написал приложение, в котором мне нужно получить информацию о текущем вошедшем в систему пользователе, когда приложение запускается, прежде чем будет обработана маршрутизация. Я использую ui-router для поддержки нескольких/вложенных представлений и предоставления более функциональной маршрутизации с отслеживанием состояния.
Когда пользователь входит в систему, он может сохранить файл cookie, представляющий его токен авторизации. Я включаю этот токен в вызов службы для получения информации о пользователе, в том числе о том, к каким группам он принадлежит. Полученное удостоверение затем задается в службе, где его можно получить и использовать в остальной части приложения. Что еще более важно, маршрутизатор будет использовать этот идентификатор, чтобы убедиться, что они вошли в систему и принадлежат к соответствующей группе, прежде чем перевести их в запрошенное состояние.
У меня есть примерно такой код:
app
.config(['$stateProvider', function($stateProvider) {
// two states; one is the protected main content, the other is the sign-in screen
$stateProvider
.state('main', {
url: '/',
data: {
roles: ['Customer', 'Staff', 'Admin']
},
views: {} // omitted
})
.state('account.signin', {
url: '/signin',
views: {} // omitted
});
}])
.run(['$rootScope', '$state', '$http', 'authority', 'principal', function($rootScope, $state, $http, authority, principal) {
$rootScope.$on('$stateChangeStart', function (event, toState) { // listen for when trying to transition states...
var isAuthenticated = principal.isAuthenticated(); // check if the user is logged in
if (!toState.data.roles || toState.data.roles.length == 0) return; // short circuit if the state has no role restrictions
if (!principal.isInAnyRole(toState.data.roles)) { // checks to see what roles the principal is a member of
event.preventDefault(); // role check failed, so...
if (isAuthenticated) $state.go('account.accessdenied'); // tell them they are accessing restricted feature
else $state.go('account.signin'); // or they simply aren't logged in yet
}
});
$http.get('/svc/account/identity') // now, looks up the current principal
.success(function(data) {
authority.authorize(data); // and then stores the principal in the service (which can be injected by requiring "principal" dependency, seen above)
}); // this does its job, but I need it to finish before responding to any routes/states
}]);
Все работает, как и ожидалось, если я вхожу в систему, перемещаюсь, выхожу из системы и т. д. Проблема заключается в том, что если я обновляю URL-адрес или перехожу по URL-адресу, когда я вошел в систему, меня отправляют на экран входа, потому что вызов службы идентификации не был завершено до изменения состояния. Однако после завершения этого вызова я мог бы продолжать работать, как и ожидалось, если есть ссылка или что-то еще, например, на состояние main
, так что я почти у цели.
Я знаю, что вы можете заставить состояния ожидать разрешения параметров перед переходом, но я не знаю, как это сделать.