[英]Handling authentication with angular front-end -> How to protect specific pages?
希望在Node.js中構建具有用戶登錄(身份驗證)功能的Web應用程序,該應用程序具有3個非安全頁面(/ home,/ contact,/ about)和一個安全頁面(/ admin)。 順便說一句,我一直在參考scotch.io Mean Machine書。
我遇到的問題是我已經將所有內容都構建好了,登錄機制的工作原理是:登錄時,我被定向到/ admin; 但是,當我不登錄而進入URL中的/ admin時,仍可以訪問該頁面。 也就是說,我不確定將實際保護放在何處。
下面是我如何布置應用程序的信息。 希望有一個概念上的答案來建議我應該如何做,而不是僅是代碼答案。
服務:
路由器:
angular.module('routerRoutes', ['ngRoute'])
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'homeController',
controllerAs: 'home'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'aboutController',
controllerAs: 'about'
})
.when('/contact', {
templateUrl: 'views/contact.html',
controller: 'contactController',
controllerAs: 'contact'
})
.when('/login', {
templateUrl: 'views/login.html',
controller: 'adminController',
controllerAs: 'login'
})
.when('/admin', {
templateUrl: 'views/admin/admin.html',
controller: 'adminController',
controllerAs: 'admin'
});
$locationProvider.html5Mode(true);
});
控制器:
homeController,aboutController和contactController通常現在為空
adminController:
.controller('adminController',function($ rootScope,$ location,Auth){
var vm = this; vm.loggedIn = Auth.isLoggedIn(); $rootScope.$on('$routeChangeStart', function() { vm.loggedIn = Auth.isLoggedIn(); window.alert(vm.loggedIn); // this gives correct answer and works Auth.getUser() .success(function(data) { vm.user = data; }); }); vm.doLogin = function() { vm.error = ''; Auth.login(vm.loginData.username, vm.loginData.password) .success(function(data) { vm.user = data.username; if (data.success) $location.path('/admin'); else vm.error = data.message; }); }; vm.doLogout = function() { Auth.logout(); vm.user = {}; $location.path('/login'); };
});
最后,下面是我的index.html(僅是正文):
<body class="container" ng-app="meanApp" ng-controller="adminController as admin">
<a href="/"><i class="fa fa-home">Home </i></a>
<a href="/about"><i class="fa fa-shield">About </i></a>
<a href="/contact"><i class="fa fa-comment">Contact</i></a>
<a href="/admin"><i class="fa fa-comment">Admin</i></a>
<ul class="nav navbar-nav navbar-right">
<li ng-if="!admin.loggedIn"><a href="/login">Login</a></li>
<li ng-if="admin.loggedIn" class="navbar-text">Hello {{ admin.user.username }}</li>
<li ng-if="admin.loggedIn"><a href="#" ng-click="admin.doLogout()">Logout</a></li>
</ul>
<main>
<div ng-view>
</div>
</main>
</body>
我將不會粘貼注入的其他html頁面,因為它們上還沒有任何東西(login.html只有兩個輸入字段和提交按鈕)。
有幾個問題:
另一個優點:
我采用了自定義屬性路由來保護應用程序中的路由。 偵聽並檢查每個發生的狀態更改是否具有此屬性。 如果設置了此屬性,則它將檢查用戶是否已登錄;如果未登錄,則會將其路由到“登錄”狀態。
我在實現該功能的當前項目中使用了UI-ROUTER。 我在路由中使用了一個自定義參數“ data”。
在.config塊中聲明我的開放路線:
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'login/login.html',
controller: 'LoginController',
controllerAs: 'vm'
})
.state('home', {
url: '',
templateUrl: 'layout/shell.html',
controller: 'ShellController',
controllerAs: 'vm',
data: {
requireLogin: true
}
})
然后,將其添加到應用程序中的.run,在其中查找ui路由器的$ stateChangeStart事件並在狀態聲明中查看我的自定義屬性(“數據”):
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
var requireLogin = toState.hasOwnProperty('data') && toState.data.requireLogin;
if (requireLogin && !authService.isLoggedIn()) {
event.preventDefault();
authService.setDestinationState(toState.name);
$state.go('login');
}
if (toState.name !== 'login') {
authService.setDestinationState(toState.name);
}
});
如果您想知道authService.setDestinationState的功能是什么...它將保留用戶嘗試訪問的URL ...一旦成功登錄,它將自動將其轉發到該狀態(請參見下文):
function login() {
authService.authLogin(vm.credentials)
.then(loginComplete)
.catch(loginFailed);
function loginComplete(data, status, headers, config) {
vm.user = data;
$rootScope.$broadcast('authorized');
$state.go(authService.getDestinationState());
}
function loginFailed(status) {
console.log('XHR Failed for login.');
vm.user = undefined;
vm.error = 'Error: Invalid user or password. ' + status.error;
toastr.error(vm.error, {closeButton: true} );
}
}
定義管理路由時,可以定義一個名為resolve的屬性。 resolve中的每個屬性都是一個函數(可以是可注入函數)。 這個函數應該返回一個promise,promise的結果可以注入到控制器中。
有關解決的更多信息,請參見http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx 。
您可以按以下方式使用resolve進行身份驗證檢查。
var authenticateRoute = ['$q', '$http' , function ($q, $http) {
var deferred = $q.defer();
$http.get("http://api.domain.com/whoami")
.then(function(response) {
if (response.data.userId) deferred.resolve(response.data.userId);
else window.location.href = "#/Login"
});
return deferred.promise();
}]
// ...
.when('/admin', {
templateUrl: 'views/admin/admin.html',
controller: 'adminController',
controllerAs: 'admin',
resolve: {
authenticatedAs: authenticateRoute
}
});
這樣,您可以傳遞經過身份驗證的用戶ID(即使為null),也可以讓控制器處理它,例如,如果您需要上下文消息。 否則,您可以執行上述操作,並且僅在身份驗證請求中有用戶ID時才這樣做,否則重定向到您的登錄路由。
希望這可以幫助! / AJ
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.