Я зараз готую кращу демонстрацію, а також прибираю деякі з цих служб у корисний модуль, але ось що я придумав. Це складний процес, щоб обійти деякі застереження, тому зависайте там. Вам потрібно буде розбити це на кілька частин.
Погляньте на цю плюшку .
По-перше, вам потрібна послуга для зберігання ідентичності користувача. Я це називаю principal
. Можна перевірити, чи користувач увійшов у систему, і за запитом він може вирішити об'єкт, який представляє важливу інформацію про особу користувача. Це може бути все, що вам потрібно, але найважливішими можуть бути відображуване ім’я, ім’я користувача, можливо, електронна пошта та ролі, яким належить користувач (якщо це стосується вашої програми). У директора також є методи перевірки ролей.
.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;
}
};
}
])
По-друге, вам потрібна служба, яка перевіряє стан, до якого хоче перейти користувач, переконайтеся, що вони увійшли (якщо це необхідно; не потрібно для входу, скидання пароля тощо), а потім перевіряють роль (якщо ваша програма потребує цього). Якщо вони не мають автентифікації, надішліть їх на сторінку входу. Якщо вони мають автентифікацію, але не виконують перевірку ролей, надішліть їх на сторінку, у якій заборонено доступ. Я дзвоню в цю службу 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');
}
}
});
}
};
}
])
Тепер все , що вам потрібно зробити , це слухати в ui-router
«з $stateChangeStart
. Це дає вам можливість вивчити поточний стан, стан, у який вони хочуть перейти, і вставити вашу перевірку авторизації. Якщо це не вдасться, ви можете скасувати перехід маршруту або змінити інший маршрут.
.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();
});
}
]);
Хитра частина щодо відстеження ідентичності користувача - це пошук, якщо ви вже пройшли автентифікацію (скажімо, ви відвідуєте сторінку після попереднього сеансу та зберегли маркер автентики у файлі cookie, або, можливо, ви сильно оновили сторінку, або випав на URL із посилання). Через те, як ui-router
працює, вам потрібно вирішити свою особу один раз, перш ніж перевірити автентичність. Ви можете зробити це за допомогою resolve
параметра в конфігурації свого стану. У мене є одна батьківська держава для сайту, від якої успадковуються всі держави, що змушує принципала вирішитись до того, як щось інше станеться.
$stateProvider.state('site', {
'abstract': true,
resolve: {
authorize: ['authorization',
function(authorization) {
return authorization.authorize();
}
]
},
template: '<div ui-view />'
})
Тут є ще одна проблема ... resolve
дзвонять лише один раз. Як тільки ваша обіцянка щодо пошуку особи завершиться, вона більше не запустить делегата рішення. Таким чином, ми повинні робити ваші автентичні перевірки у двох місцях: один раз відповідно до вашої особи, яка обіцяє вирішити проблему resolve
, яка охоплює перший час завантаження вашої програми, і один раз, $stateChangeStart
якщо дозвіл було зроблено, яке охоплює будь-який час, коли ви переходите до штатів.
Гаразд, що ж ми зробили досі?
- Ми перевіряємо, коли програма завантажується, якщо користувач увійшов у систему.
- Ми відстежуємо інформацію про зареєстрованого користувача.
- Ми перенаправляємо їх для входу в стан для держав, які вимагають від користувача входу.
- Ми перенаправляємо їх у стан, яким заборонено доступ, якщо вони не мають дозволу на доступ до нього.
- У нас є механізм перенаправлення користувачів до початкового стану, про який вони запитували, якщо вони нам потрібні для входу.
- Ми можемо вийти з користувача (його потрібно узгоджувати з будь-яким клієнтським або серверним кодом, який керує вашим авторським квитком).
- Нам не потрібно відправляти користувачів на сторінку входу щоразу, коли вони перезавантажують свій веб-переглядач або переходять за посиланням.
Куди ми підемо звідси? Ну, ви можете організувати свої статки в регіони , які вимагають увійти. Ви можете вимагати перевірку справжності / авторизованих користувачів, додаючи data
з roles
цими станами (або одного з батьків з них, якщо ви хочете використовувати спадкування). Тут ми обмежуємо ресурс для адміністраторів:
.state('restricted', {
parent: 'site',
url: '/restricted',
data: {
roles: ['Admin']
},
views: {
'content@': {
templateUrl: 'restricted.html'
}
}
})
Тепер ви можете керувати державою, які користувачі можуть отримати доступ до маршруту. Будь-які інші проблеми? Можливо, змінюється лише частина перегляду залежно від того, чи вони ввійшли чи ні? Нема проблем. Використовуйте principal.isAuthenticated()
або навіть principal.isInRole()
будь-яким із численних способів умовно відобразити шаблон або елемент.
По-перше, введіть principal
у контролер чи будь-що інше, і приклейте його до області, щоб ви могли легко використовувати його у вашому представленні:
.scope('HomeCtrl', ['$scope', 'principal',
function($scope, principal)
{
$scope.principal = principal;
});
Показати або приховати елемент:
<div ng-show="principal.isAuthenticated()">
I'm logged in
</div>
<div ng-hide="principal.isAuthenticated()">
I'm not logged in
</div>
І т.д., і так далі, і так далі. У будь-якому випадку, у вашому прикладі програми ви матимете стан для домашньої сторінки, завдяки якому неправдиві користувачі можуть опускатися. Вони можуть мати посилання на стан входу або реєстрації або вбудовувати ці форми на цю сторінку. Що б вам не підходило.
Усі сторінки інформаційної панелі можуть успадковувати стан, який вимагає, щоб користувачі входили в систему і, скажімо, були User
учасниками ролі. Усі матеріали про авторизацію, про які ми говорили, надходитимуть звідти.